mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
🐛 Fix e2e tests for plugins
This commit is contained in:
parent
bd7f4dca3a
commit
449aa65f8d
@ -126,6 +126,6 @@
|
|||||||
|
|
||||||
(defn check-permission
|
(defn check-permission
|
||||||
[plugin-id permission]
|
[plugin-id permission]
|
||||||
(or (= plugin-id "TEST")
|
(or (= plugin-id "00000000-0000-0000-0000-000000000000")
|
||||||
(let [{:keys [permissions]} (dm/get-in @registry [:data plugin-id])]
|
(let [{:keys [permissions]} (dm/get-in @registry [:data plugin-id])]
|
||||||
(contains? permissions permission))))
|
(contains? permissions permission))))
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
store (ths/setup-store (cthf/sample-file :file1 :page-label :page1))
|
store (ths/setup-store (cthf/sample-file :file1 :page-label :page1))
|
||||||
|
|
||||||
^js context (api/create-context "TEST")
|
^js context (api/create-context "00000000-0000-0000-0000-000000000000")
|
||||||
|
|
||||||
_ (set! st/state store)
|
_ (set! st/state store)
|
||||||
|
|
||||||
|
|||||||
@ -28,5 +28,5 @@ export default [
|
|||||||
files: ['**/*.js', '**/*.jsx'],
|
files: ['**/*.js', '**/*.jsx'],
|
||||||
rules: {},
|
rules: {},
|
||||||
},
|
},
|
||||||
{ ignores: ['vite.config.ts'] },
|
{ ignores: ['vite.config.ts', 'vitest.setup.ts'] },
|
||||||
];
|
];
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@ import comments from './plugins/create-comments';
|
|||||||
import { Agent } from './utils/agent';
|
import { Agent } from './utils/agent';
|
||||||
|
|
||||||
describe('Plugins', () => {
|
describe('Plugins', () => {
|
||||||
it.only('create board - text - rectable', async () => {
|
it('create board - text - rectable', async () => {
|
||||||
const agent = await Agent();
|
const agent = await Agent();
|
||||||
const result = await agent.runCode(testingPlugin.toString(), {
|
const result = await agent.runCode(testingPlugin.toString(), {
|
||||||
screenshot: 'create-board-text-rect',
|
screenshot: 'create-board-text-rect',
|
||||||
@ -29,6 +29,7 @@ describe('Plugins', () => {
|
|||||||
|
|
||||||
it('create grid layout', async () => {
|
it('create grid layout', async () => {
|
||||||
const agent = await Agent();
|
const agent = await Agent();
|
||||||
|
|
||||||
const result = await agent.runCode(grid.toString(), {
|
const result = await agent.runCode(grid.toString(), {
|
||||||
screenshot: 'create-gridlayout',
|
screenshot: 'create-gridlayout',
|
||||||
});
|
});
|
||||||
@ -83,9 +84,9 @@ describe('Plugins', () => {
|
|||||||
|
|
||||||
it('comments', async () => {
|
it('comments', async () => {
|
||||||
const agent = await Agent();
|
const agent = await Agent();
|
||||||
|
console.log(comments.toString());
|
||||||
const result = await agent.runCode(comments.toString(), {
|
const result = await agent.runCode(comments.toString(), {
|
||||||
screenshot: 'create-comments',
|
screenshot: 'create-comments',
|
||||||
avoidSavedStatus: true,
|
|
||||||
});
|
});
|
||||||
expect(result).toMatchSnapshot();
|
expect(result).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import puppeteer from 'puppeteer';
|
import puppeteer, { ConsoleMessage } from 'puppeteer';
|
||||||
import { PenpotApi } from './api';
|
import { PenpotApi } from './api';
|
||||||
import { getFileUrl } from './get-file-url';
|
import { getFileUrl } from './get-file-url';
|
||||||
import { idObjectToArray } from './clean-id';
|
import { idObjectToArray } from './clean-id';
|
||||||
@ -56,7 +56,10 @@ export async function Agent() {
|
|||||||
console.log('File URL:', fileUrl);
|
console.log('File URL:', fileUrl);
|
||||||
|
|
||||||
console.log('Launching browser...');
|
console.log('Launching browser...');
|
||||||
const browser = await puppeteer.launch({args: ['--ignore-certificate-errors']});
|
const browser = await puppeteer.launch({
|
||||||
|
headless: process.env['E2E_HEADLESS'] !== 'false',
|
||||||
|
args: ['--ignore-certificate-errors'],
|
||||||
|
});
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
|
|
||||||
await page.setViewport({ width: 1920, height: 1080 });
|
await page.setViewport({ width: 1920, height: 1080 });
|
||||||
@ -88,8 +91,11 @@ export async function Agent() {
|
|||||||
|
|
||||||
const finish = async () => {
|
const finish = async () => {
|
||||||
console.log('Deleting file and closing browser...');
|
console.log('Deleting file and closing browser...');
|
||||||
await penpotApi.deleteFile(file['~:id']);
|
// TODO
|
||||||
await browser.close();
|
// await penpotApi.deleteFile(file['~:id']);
|
||||||
|
if (process.env['E2E_CLOSE_BROWSER'] !== 'false') {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
console.log('Clean up done.');
|
console.log('Clean up done.');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,11 +105,9 @@ export async function Agent() {
|
|||||||
options: {
|
options: {
|
||||||
screenshot?: string;
|
screenshot?: string;
|
||||||
autoFinish?: boolean;
|
autoFinish?: boolean;
|
||||||
avoidSavedStatus?: boolean;
|
|
||||||
} = {
|
} = {
|
||||||
screenshot: '',
|
screenshot: '',
|
||||||
autoFinish: true,
|
autoFinish: true,
|
||||||
avoidSavedStatus: false,
|
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const autoFinish = options.autoFinish ?? true;
|
const autoFinish = options.autoFinish ?? true;
|
||||||
@ -112,28 +116,27 @@ export async function Agent() {
|
|||||||
await page.evaluate((testingPlugin) => {
|
await page.evaluate((testingPlugin) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(globalThis as any).ɵloadPlugin({
|
(globalThis as any).ɵloadPlugin({
|
||||||
pluginId: 'TEST',
|
pluginId: '00000000-0000-0000-0000-000000000000',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
code: `
|
code: `
|
||||||
(${testingPlugin})();
|
(${testingPlugin})();
|
||||||
`,
|
`,
|
||||||
icon: '',
|
icon: '',
|
||||||
description: '',
|
description: '',
|
||||||
permissions: ['content:read', 'content:write'],
|
permissions: [
|
||||||
|
'content:read',
|
||||||
|
'content:write',
|
||||||
|
'library:read',
|
||||||
|
'library:write',
|
||||||
|
'user:read',
|
||||||
|
'comment:read',
|
||||||
|
'comment:write',
|
||||||
|
'allow:downloads',
|
||||||
|
'allow:localstorage',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}, code);
|
}, code);
|
||||||
|
|
||||||
if (!options.avoidSavedStatus) {
|
|
||||||
console.log('Waiting for save status...');
|
|
||||||
await page.waitForSelector(
|
|
||||||
'.main_ui_workspace_right_header__saved-status',
|
|
||||||
{
|
|
||||||
timeout: 10000,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
console.log('Save status found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.screenshot && screenshotsEnable) {
|
if (options.screenshot && screenshotsEnable) {
|
||||||
console.log('Taking screenshot:', options.screenshot);
|
console.log('Taking screenshot:', options.screenshot);
|
||||||
await page.screenshot({
|
await page.screenshot({
|
||||||
@ -141,30 +144,55 @@ export async function Agent() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
const result = await new Promise((resolve) => {
|
||||||
page.once('console', async (msg) => {
|
const handleConsole = async (msg: ConsoleMessage) => {
|
||||||
const args = (await Promise.all(
|
const args = (await Promise.all(
|
||||||
msg.args().map((arg) => arg.jsonValue()),
|
msg.args().map((arg) => arg.jsonValue()),
|
||||||
)) as Record<string, unknown>[];
|
)) as unknown[];
|
||||||
|
|
||||||
const result = Object.values(args[1]) as Shape[];
|
const type = args[0];
|
||||||
|
const data = args[1];
|
||||||
|
|
||||||
|
if (type !== 'objects' || !data || typeof data !== 'object') {
|
||||||
|
console.log('Invalid console message, waiting for valid one...');
|
||||||
|
page.once('console', handleConsole);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = Object.values(data) as Shape[];
|
||||||
|
|
||||||
replaceIds(result);
|
replaceIds(result);
|
||||||
console.log('IDs replaced in result.');
|
console.log('IDs replaced in result.');
|
||||||
|
|
||||||
resolve(result);
|
resolve(result);
|
||||||
|
};
|
||||||
|
|
||||||
if (autoFinish) {
|
page.once('console', handleConsole);
|
||||||
console.log('Auto finish enabled. Cleaning up...');
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Evaluating debug.dump_objects...');
|
console.log('Evaluating debug.dump_objects...');
|
||||||
page.evaluate(`
|
page.evaluate(`
|
||||||
debug.dump_objects();
|
debug.dump_objects();
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await page.waitForNetworkIdle({ idleTime: 2000 });
|
||||||
|
|
||||||
|
// Wait for the update-file API call to complete
|
||||||
|
if (process.env['E2E_WAIT_API_RESPONSE'] === 'true') {
|
||||||
|
await page.waitForResponse(
|
||||||
|
(response) =>
|
||||||
|
response.url().includes('api/main/methods/update-file') &&
|
||||||
|
response.status() === 200,
|
||||||
|
{ timeout: 10000 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoFinish) {
|
||||||
|
console.log('Auto finish enabled. Cleaning up...');
|
||||||
|
await finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
},
|
},
|
||||||
finish,
|
finish,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { FileRpc } from '../models/file-rpc.model';
|
import { FileRpc } from '../models/file-rpc.model';
|
||||||
|
|
||||||
const apiUrl = 'https://localhost:3449';
|
const apiUrl = 'https://localhost:3449';
|
||||||
|
|
||||||
export async function PenpotApi() {
|
export async function PenpotApi() {
|
||||||
@ -8,8 +7,8 @@ export async function PenpotApi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
'email': process.env['E2E_LOGIN_EMAIL'],
|
email: process.env['E2E_LOGIN_EMAIL'],
|
||||||
'password': process.env['E2E_LOGIN_PASSWORD'],
|
password: process.env['E2E_LOGIN_PASSWORD'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const resultLoginRequest = await fetch(
|
const resultLoginRequest = await fetch(
|
||||||
@ -18,25 +17,18 @@ export async function PenpotApi() {
|
|||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: body
|
body: body,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("AAAAAAAAAAAA", 1, apiUrl)
|
|
||||||
// console.log("AAAAAAAAAAAA", 2, resultLoginRequest);
|
|
||||||
|
|
||||||
console.dir(resultLoginRequest.headers, {depth:20});
|
|
||||||
console.log('Document Cookies:', window.document.cookie);
|
|
||||||
|
|
||||||
const loginData = await resultLoginRequest.json();
|
const loginData = await resultLoginRequest.json();
|
||||||
|
|
||||||
|
|
||||||
const authToken = resultLoginRequest.headers
|
const authToken = resultLoginRequest.headers
|
||||||
.get('set-cookie')
|
.getSetCookie()
|
||||||
?.split(';')
|
.find((cookie: string) => cookie.startsWith('auth-token='))
|
||||||
.at(0);
|
?.split(';')[0];
|
||||||
|
|
||||||
if (!authToken) {
|
if (!authToken) {
|
||||||
throw new Error('Login failed');
|
throw new Error('Login failed');
|
||||||
@ -62,6 +54,9 @@ export async function PenpotApi() {
|
|||||||
'fdata/objects-map',
|
'fdata/objects-map',
|
||||||
'fdata/pointer-map',
|
'fdata/pointer-map',
|
||||||
'fdata/shape-data-type',
|
'fdata/shape-data-type',
|
||||||
|
'fdata/path-data',
|
||||||
|
'design-tokens/v1',
|
||||||
|
'variants/v1',
|
||||||
'components/v2',
|
'components/v2',
|
||||||
'styles/v2',
|
'styles/v2',
|
||||||
'layout/grid',
|
'layout/grid',
|
||||||
@ -72,7 +67,9 @@ export async function PenpotApi() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return (await createFileRequest.json()) as FileRpc;
|
const fileData = (await createFileRequest.json()) as FileRpc;
|
||||||
|
console.log('File data received:', fileData);
|
||||||
|
return fileData;
|
||||||
},
|
},
|
||||||
deleteFile: async (fileId: string) => {
|
deleteFile: async (fileId: string) => {
|
||||||
const deleteFileRequest = await fetch(
|
const deleteFileRequest = await fetch(
|
||||||
|
|||||||
@ -6,5 +6,5 @@ export function getFileUrl(file: FileRpc) {
|
|||||||
const fileId = cleanId(file['~:id']);
|
const fileId = cleanId(file['~:id']);
|
||||||
const pageId = cleanId(file['~:data']['~:pages'][0]);
|
const pageId = cleanId(file['~:data']['~:pages'][0]);
|
||||||
|
|
||||||
return `http://localhost:3449/#/workspace/${projectId}/${fileId}?page-id=${pageId}`;
|
return `https://localhost:3449/#/workspace/${projectId}/${fileId}?page-id=${pageId}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,13 +7,27 @@ export default defineConfig({
|
|||||||
testTimeout: 20000,
|
testTimeout: 20000,
|
||||||
watch: false,
|
watch: false,
|
||||||
globals: true,
|
globals: true,
|
||||||
environment: 'happy-dom',
|
environment: 'node',
|
||||||
|
environmentOptions: {
|
||||||
|
happyDOM: {
|
||||||
|
settings: {
|
||||||
|
disableCSSFileLoading: true,
|
||||||
|
disableJavaScriptFileLoading: true,
|
||||||
|
disableJavaScriptEvaluation: true,
|
||||||
|
enableFileSystemHttpRequests: false,
|
||||||
|
navigator: {
|
||||||
|
userAgent:
|
||||||
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
reporters: ['default'],
|
reporters: ['default'],
|
||||||
coverage: {
|
coverage: {
|
||||||
reportsDirectory: '../coverage/e2e',
|
reportsDirectory: '../coverage/e2e',
|
||||||
provider: 'v8',
|
provider: 'v8',
|
||||||
},
|
},
|
||||||
setupFiles: ['dotenv/config', 'vitest.setup.ts']
|
setupFiles: ['dotenv/config', 'vitest.setup.ts'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1 @@
|
|||||||
// import { vi } from 'vitest';
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||||
|
|
||||||
window.location.href = 'https://localhost:3449';
|
|
||||||
|
|||||||
@ -9,7 +9,10 @@
|
|||||||
```env
|
```env
|
||||||
E2E_LOGIN_EMAIL="test@penpot.app"
|
E2E_LOGIN_EMAIL="test@penpot.app"
|
||||||
E2E_LOGIN_PASSWORD="123123123"
|
E2E_LOGIN_PASSWORD="123123123"
|
||||||
E2E_SCREENSHOTS= "true"
|
E2E_SCREENSHOTS="true" # Enable/disable screenshots (default: false)
|
||||||
|
E2E_HEADLESS="false" # Run browser in headless mode (default: true)
|
||||||
|
E2E_CLOSE_BROWSER="true" # Close browser after tests (default: true)
|
||||||
|
E2E_WAIT_API_RESPONSE="false" # Wait for update-file API response (default: false)
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Run E2E Tests**
|
2. **Run E2E Tests**
|
||||||
@ -77,5 +80,5 @@
|
|||||||
If you need to refresh all the snapshopts run the test with the update option:
|
If you need to refresh all the snapshopts run the test with the update option:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm run test:e2e -- --update
|
pnpm run test:e2e --update
|
||||||
```
|
```
|
||||||
|
|||||||
@ -28,7 +28,9 @@ export const initPluginsRuntime = (contextBuilder: (id: string) => Context) => {
|
|||||||
try {
|
try {
|
||||||
console.log('%c[PLUGINS] Initialize runtime', 'color: #008d7c');
|
console.log('%c[PLUGINS] Initialize runtime', 'color: #008d7c');
|
||||||
setContextBuilder(contextBuilder);
|
setContextBuilder(contextBuilder);
|
||||||
globalThisAny$.ɵcontext = contextBuilder('TEST');
|
globalThisAny$.ɵcontext = contextBuilder(
|
||||||
|
'00000000-0000-0000-0000-000000000000',
|
||||||
|
);
|
||||||
globalThis.ɵloadPlugin = ɵloadPlugin;
|
globalThis.ɵloadPlugin = ɵloadPlugin;
|
||||||
globalThis.ɵloadPluginByUrl = ɵloadPluginByUrl;
|
globalThis.ɵloadPluginByUrl = ɵloadPluginByUrl;
|
||||||
globalThis.ɵunloadPlugin = ɵunloadPlugin;
|
globalThis.ɵunloadPlugin = ɵunloadPlugin;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user