mirror of
https://github.com/maputnik/editor.git
synced 2026-08-27 15:37:27 +00:00
Reduce export surface
This commit is contained in:
+6
-13
@@ -1,11 +1,4 @@
|
|||||||
import {
|
import { Assertable, PlaywrightHelper } from "./playwright-helper";
|
||||||
Assertable,
|
|
||||||
PlaywrightHelper,
|
|
||||||
Query,
|
|
||||||
assertDeepNestedInclude,
|
|
||||||
readFixture,
|
|
||||||
retry,
|
|
||||||
} from "./playwright-helper";
|
|
||||||
import { ModalDriver } from "./modal-driver";
|
import { ModalDriver } from "./modal-driver";
|
||||||
|
|
||||||
const baseUrl = "http://localhost:8888/";
|
const baseUrl = "http://localhost:8888/";
|
||||||
@@ -22,9 +15,9 @@ export class MaputnikAssertable<T> extends Assertable<T> {
|
|||||||
*/
|
*/
|
||||||
shouldEqualToStoredStyle = async () => {
|
shouldEqualToStoredStyle = async () => {
|
||||||
const expected = await (this.target as any);
|
const expected = await (this.target as any);
|
||||||
await retry(async () => {
|
await this.retry(async () => {
|
||||||
const stored = await this.getStoredStyle();
|
const stored = await this.getStoredStyle();
|
||||||
assertDeepNestedInclude(expected, stored);
|
this.assertDeepNestedInclude(expected, stored);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -202,14 +195,14 @@ export class MaputnikDriver {
|
|||||||
|
|
||||||
skipTargetLayerEditor: () => this.helper.get.elementByTestId("skip-target-layer-editor"),
|
skipTargetLayerEditor: () => this.helper.get.elementByTestId("skip-target-layer-editor"),
|
||||||
|
|
||||||
styleFromLocalStorage: () => new Query<any>(() => this.readStoredStyle()),
|
styleFromLocalStorage: () => this.helper.query(() => this.readStoredStyle()),
|
||||||
|
|
||||||
fixture: (name: string) => Promise.resolve(readFixture(name)),
|
fixture: (name: string) => Promise.resolve(this.helper.readFixture(name)),
|
||||||
|
|
||||||
responseBody: (alias: string) => {
|
responseBody: (alias: string) => {
|
||||||
// Our mocked style responses always return the matching fixture.
|
// Our mocked style responses always return the matching fixture.
|
||||||
const name = alias.endsWith(".json") ? alias : `${alias}.json`;
|
const name = alias.endsWith(".json") ? alias : `${alias}.json`;
|
||||||
return Promise.resolve(readFixture(name));
|
return Promise.resolve(this.helper.readFixture(name));
|
||||||
},
|
},
|
||||||
|
|
||||||
exampleFileUrl: () => baseUrl + "example-style.json",
|
exampleFileUrl: () => baseUrl + "example-style.json",
|
||||||
|
|||||||
+23
-13
@@ -8,17 +8,12 @@ const DATA_ATTRIBUTE = "data-wd-key";
|
|||||||
const FIXTURES_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), "fixtures");
|
const FIXTURES_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), "fixtures");
|
||||||
const isMac = process.platform === "darwin";
|
const isMac = process.platform === "darwin";
|
||||||
|
|
||||||
export function testIdSelector(testId: string): string {
|
function testIdSelector(testId: string): string {
|
||||||
return `[${DATA_ATTRIBUTE}="${testId}"]`;
|
return `[${DATA_ATTRIBUTE}="${testId}"]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readFixture(name: string): any {
|
|
||||||
const contents = fs.readFileSync(path.join(FIXTURES_DIR, name), "utf-8");
|
|
||||||
return JSON.parse(contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retries `assertion` until it stops throwing */
|
/** Retries `assertion` until it stops throwing */
|
||||||
export async function retry(
|
async function retry(
|
||||||
assertion: () => Promise<void> | void,
|
assertion: () => Promise<void> | void,
|
||||||
timeout = 10000,
|
timeout = 10000,
|
||||||
interval = 100
|
interval = 100
|
||||||
@@ -41,7 +36,7 @@ export async function retry(
|
|||||||
* A lazily-evaluated value (e.g. the style in localStorage). Assertions on a
|
* A lazily-evaluated value (e.g. the style in localStorage). Assertions on a
|
||||||
* Query re-read the value until they pass.
|
* Query re-read the value until they pass.
|
||||||
*/
|
*/
|
||||||
export class Query<T> {
|
class Query<T> {
|
||||||
readonly __query = true as const;
|
readonly __query = true as const;
|
||||||
constructor(private readonly getter: () => Promise<T>) {}
|
constructor(private readonly getter: () => Promise<T>) {}
|
||||||
|
|
||||||
@@ -68,7 +63,7 @@ function isLocator(target: unknown): target is Locator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Asserts that every top-level key in `expected` deep-equals its counterpart in `actual`. */
|
/** Asserts that every top-level key in `expected` deep-equals its counterpart in `actual`. */
|
||||||
export function assertDeepNestedInclude(actual: any, expected: Record<string, unknown>): void {
|
function assertDeepNestedInclude(actual: any, expected: Record<string, unknown>): void {
|
||||||
for (const key of Object.keys(expected)) {
|
for (const key of Object.keys(expected)) {
|
||||||
expect(actual?.[key], `property "${key}"`).toEqual(expected[key]);
|
expect(actual?.[key], `property "${key}"`).toEqual(expected[key]);
|
||||||
}
|
}
|
||||||
@@ -82,6 +77,11 @@ export function assertDeepNestedInclude(actual: any, expected: Record<string, un
|
|||||||
export class Assertable<T> {
|
export class Assertable<T> {
|
||||||
constructor(protected readonly target: T) {}
|
constructor(protected readonly target: T) {}
|
||||||
|
|
||||||
|
// Exposed to subclasses (e.g. MaputnikAssertable) so custom assertions can be
|
||||||
|
// built without re-importing these module-private helpers.
|
||||||
|
protected readonly retry = retry;
|
||||||
|
protected readonly assertDeepNestedInclude = assertDeepNestedInclude;
|
||||||
|
|
||||||
private locator(): Locator {
|
private locator(): Locator {
|
||||||
if (!isLocator(this.target)) throw new Error("Expected a Locator target for this assertion");
|
if (!isLocator(this.target)) throw new Error("Expected a Locator target for this assertion");
|
||||||
return this.target;
|
return this.target;
|
||||||
@@ -139,7 +139,7 @@ export class Assertable<T> {
|
|||||||
this.assertValue((actual) => assertDeepNestedInclude(actual, value));
|
this.assertValue((actual) => assertDeepNestedInclude(actual, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function typeSequence(page: Page, text: string): Promise<void> {
|
async function typeSequence(page: Page, text: string): Promise<void> {
|
||||||
const tokens = text.match(/\{[^}]+\}|[^{]+/g) ?? [];
|
const tokens = text.match(/\{[^}]+\}|[^{]+/g) ?? [];
|
||||||
const modifierMap: Record<string, string> = { meta: "Meta", ctrl: "Control", shift: "Shift", alt: "Alt" };
|
const modifierMap: Record<string, string> = { meta: "Meta", ctrl: "Control", shift: "Shift", alt: "Alt" };
|
||||||
const namedKeys: Record<string, string> = {
|
const namedKeys: Record<string, string> = {
|
||||||
@@ -197,6 +197,16 @@ export class PlaywrightHelper {
|
|||||||
return this.page.locator(testIdSelector(testId));
|
return this.page.locator(testIdSelector(testId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Reads and parses a JSON fixture from the fixtures directory. */
|
||||||
|
public readFixture(name: string): any {
|
||||||
|
return JSON.parse(fs.readFileSync(path.join(FIXTURES_DIR, name), "utf-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Wraps a lazily-evaluated value so assertions on it auto-retry. */
|
||||||
|
public query<T>(getter: () => Promise<T>): Query<T> {
|
||||||
|
return new Query<T>(getter);
|
||||||
|
}
|
||||||
|
|
||||||
public given = {
|
public given = {
|
||||||
intercept: async (pattern: RegExp, alias: string, _method = "GET") => {
|
intercept: async (pattern: RegExp, alias: string, _method = "GET") => {
|
||||||
this.recordedRequests.set(alias, []);
|
this.recordedRequests.set(alias, []);
|
||||||
@@ -218,7 +228,7 @@ export class PlaywrightHelper {
|
|||||||
if (alias) this.recordedRequests.get(alias)!.push(route.request());
|
if (alias) this.recordedRequests.get(alias)!.push(route.request());
|
||||||
const body =
|
const body =
|
||||||
response && typeof response === "object" && "fixture" in (response as any)
|
response && typeof response === "object" && "fixture" in (response as any)
|
||||||
? readFixture((response as { fixture: string }).fixture)
|
? this.readFixture((response as { fixture: string }).fixture)
|
||||||
: response;
|
: response;
|
||||||
route.fulfill({ json: body });
|
route.fulfill({ json: body });
|
||||||
});
|
});
|
||||||
@@ -326,7 +336,7 @@ export class PlaywrightHelper {
|
|||||||
},
|
},
|
||||||
|
|
||||||
openFileByFixture: async (fixture: string, buttonTestId: string, inputTestId: string) => {
|
openFileByFixture: async (fixture: string, buttonTestId: string, inputTestId: string) => {
|
||||||
const content = JSON.stringify(readFixture(fixture));
|
const content = JSON.stringify(this.readFixture(fixture));
|
||||||
const hasPicker = await this.page.evaluate(() => "showOpenFilePicker" in window);
|
const hasPicker = await this.page.evaluate(() => "showOpenFilePicker" in window);
|
||||||
if (hasPicker) {
|
if (hasPicker) {
|
||||||
await this.page.evaluate((fileContent) => {
|
await this.page.evaluate((fileContent) => {
|
||||||
@@ -345,7 +355,7 @@ export class PlaywrightHelper {
|
|||||||
},
|
},
|
||||||
|
|
||||||
dropFileByFixture: async (fixture: string, dropzoneTestId: string) => {
|
dropFileByFixture: async (fixture: string, dropzoneTestId: string) => {
|
||||||
const content = JSON.stringify(readFixture(fixture));
|
const content = JSON.stringify(this.readFixture(fixture));
|
||||||
const dataTransfer = await this.page.evaluateHandle((fileContent) => {
|
const dataTransfer = await this.page.evaluateHandle((fileContent) => {
|
||||||
const dt = new DataTransfer();
|
const dt = new DataTransfer();
|
||||||
dt.items.add(new File([fileContent], "example-style.json", { type: "application/json" }));
|
dt.items.add(new File([fileContent], "example-style.json", { type: "application/json" }));
|
||||||
|
|||||||
Reference in New Issue
Block a user