mirror of
https://github.com/penpot/penpot.git
synced 2026-11-12 13:00:37 +00:00
A review found tests that would pass with what they test broken. - Runners: both judge one variant at a time, fail a variant with no assertion and a known-failure mark that applies nowhere, and give the asserter the state the operations produced. The pure runner validates the final file and rejects operations of unknown kind. The frontend interpreter fails a step when the store reports an event error (Potok only logs it), reports asserter errors against their case, and stops the watchers that install! starts. - Nodes drive the real code: a main root rename goes through end-rename-shape, and the clipboard's advance of nested copies is one common function, cll/advance-copied-objects, that copy-selected and both test paths call. - Cases N, AH, AI, AK, AD, AE, K, C, H, S, AY, I, Y, AX and F check what they claim; O, R and T get real sizes. - Stricter common unit tests found F60 (a repair detaches healthy copies), F61 (a switch drops a fixed-sizing size), F62 (the ref chain never stops at its target) and F63 (latent); all pinned. - Frontend library tests: the RPC double records on subscribe, the dropped commits check that nothing syncs, and the link and share tests check the events sent. - Plugin suite: OpSwap and OpDetach throw when the API call did nothing, and case AB checks that the reset head is an instance of the original component. - The composable suite memory records the new rules.
46 lines
1.7 KiB
TypeScript
46 lines
1.7 KiB
TypeScript
import { LibraryComponent } from "@penpot/plugin-types";
|
|
import { Operation } from "../core/Operation";
|
|
import { Situation } from "../core/Situation";
|
|
import { ShapeTarget, resolveTarget } from "../core/ShapeTarget";
|
|
import { PenpotSync } from "../util/PenpotSync";
|
|
|
|
/**
|
|
* Swaps the copy head a target resolves to for an instance of another
|
|
* component, via the Plugin API's `swapComponent()`. The new head keeps the
|
|
* old head's id, so a target that found the old head finds the new one.
|
|
*
|
|
* Unlike the swap in the workspace UI, the API keeps the head's overrides
|
|
* (it swaps with keep-touched, F33 in the stabilization plan).
|
|
*/
|
|
export class OpSwap extends Operation {
|
|
/**
|
|
* @param target - resolves the copy head to swap
|
|
* @param component - resolves the component to swap to
|
|
* @param label - a human-readable description of the swap, used in the
|
|
* applied-operation log
|
|
*/
|
|
constructor(
|
|
private readonly target: ShapeTarget,
|
|
private readonly component: (situation: Situation) => LibraryComponent,
|
|
private readonly label: string
|
|
) {
|
|
super();
|
|
}
|
|
|
|
async applyTo(situation: Situation): Promise<void> {
|
|
// act on the settled document, as a user would
|
|
await PenpotSync.awaitPropagation();
|
|
const to = this.component(situation);
|
|
resolveTarget(this.target, situation).swapComponent(to);
|
|
await PenpotSync.awaitPropagation();
|
|
// an API call that fails only logs, so a case would go on as if nothing happened
|
|
if (resolveTarget(this.target, situation).component()?.id !== to.id) {
|
|
throw new Error(`the swap did not take effect: ${this}`);
|
|
}
|
|
}
|
|
|
|
toString(): string {
|
|
return `swap ${this.label}`;
|
|
}
|
|
}
|