chore: Add playwright tests
This commit is contained in:
+22
-19
@@ -7,13 +7,11 @@ on:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
cypress-run:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# run 3 copies of the current job in parallel
|
||||
containers: [1, 2, 3]
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright:v1.42.1-jammy
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -23,7 +21,6 @@ jobs:
|
||||
id: pnpm-and-build-cache
|
||||
with:
|
||||
path: |
|
||||
~/.cache/Cypress
|
||||
build
|
||||
node_modules
|
||||
key: ${{ runner.os }}-node_modules-build-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
@@ -38,16 +35,22 @@ jobs:
|
||||
node-version-file: '.node-version'
|
||||
cache: 'pnpm'
|
||||
|
||||
# Install NPM dependencies, cache them correctly
|
||||
# and run all Cypress tests
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v6
|
||||
with:
|
||||
build: pnpm build
|
||||
start: pnpm preview
|
||||
wait-on: 'http://localhost:3000'
|
||||
record: true
|
||||
parallel: true
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: |
|
||||
pnpm preview &
|
||||
pnpm test:e2e
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
CYPRESS_CI: true
|
||||
CI: true
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
|
||||
@@ -12,3 +12,9 @@
|
||||
/functions
|
||||
/node_modules
|
||||
/snapshots.js
|
||||
|
||||
# Playwright
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
||||
+6
-2
@@ -19,7 +19,10 @@
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"test:browser": "cypress run",
|
||||
"test": "pnpm test:unit && pnpm test:browser",
|
||||
"cy": "cypress open"
|
||||
"cy": "cypress open",
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui",
|
||||
"test:e2e:debug": "playwright test --debug"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/snapshot": "2.1.7",
|
||||
@@ -69,7 +72,8 @@
|
||||
"typescript": "^5.5.4",
|
||||
"vite": "^5.4.14",
|
||||
"vitest": "^2.1.9",
|
||||
"vitest-dom": "^0.1.1"
|
||||
"vitest-dom": "^0.1.1",
|
||||
"@playwright/test": "^1.42.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mermaid-js/layout-elk": "^0.1.7",
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
fullyParallel: true,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
reporter: 'html',
|
||||
use: {
|
||||
baseURL: 'http://localhost:3000',
|
||||
trace: 'on-first-retry',
|
||||
viewport: { width: 1920, height: 768 }
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] }
|
||||
}
|
||||
],
|
||||
webServer: {
|
||||
command: 'pnpm run dev',
|
||||
url: 'http://localhost:3000',
|
||||
reuseExistingServer: !process.env.CI
|
||||
}
|
||||
});
|
||||
Generated
+38
@@ -57,6 +57,9 @@ importers:
|
||||
'@fortawesome/fontawesome-free':
|
||||
specifier: ^6.5.2
|
||||
version: 6.7.2
|
||||
'@playwright/test':
|
||||
specifier: ^1.42.1
|
||||
version: 1.51.1
|
||||
'@sveltejs/adapter-static':
|
||||
specifier: 3.0.8
|
||||
version: 3.0.8(@sveltejs/kit@2.20.0(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.23.1)(vite@5.4.14))(svelte@5.23.1)(vite@5.4.14))
|
||||
@@ -571,6 +574,11 @@ packages:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@playwright/test@1.51.1':
|
||||
resolution: {integrity: sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
'@polka/url@1.0.0-next.28':
|
||||
resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==}
|
||||
|
||||
@@ -2209,6 +2217,11 @@ packages:
|
||||
fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
fsevents@2.3.2:
|
||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
@@ -3059,6 +3072,16 @@ packages:
|
||||
resolution: {integrity: sha512-hMhneYm3GCPyQon88SZrVJx+LlqhM1kZFQbuAgXPoh/Az2YvO1B6bitT9qlhpiTdJlsT5lsr3gPmzoVjb5CDXA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
playwright-core@1.51.1:
|
||||
resolution: {integrity: sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
playwright@1.51.1:
|
||||
resolution: {integrity: sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
pluralize@8.0.0:
|
||||
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -4650,6 +4673,10 @@ snapshots:
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@playwright/test@1.51.1':
|
||||
dependencies:
|
||||
playwright: 1.51.1
|
||||
|
||||
'@polka/url@1.0.0-next.28': {}
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.35.0':
|
||||
@@ -6525,6 +6552,9 @@ snapshots:
|
||||
|
||||
fs.realpath@1.0.0: {}
|
||||
|
||||
fsevents@2.3.2:
|
||||
optional: true
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
@@ -7350,6 +7380,14 @@ snapshots:
|
||||
|
||||
plausible-tracker@0.3.9: {}
|
||||
|
||||
playwright-core@1.51.1: {}
|
||||
|
||||
playwright@1.51.1:
|
||||
dependencies:
|
||||
playwright-core: 1.51.1
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
pluralize@8.0.0: {}
|
||||
|
||||
points-on-curve@0.2.0: {}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { typeInEditor, verifyFileSizeGreaterThan } from './utils';
|
||||
|
||||
test.describe('Check actions', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/edit');
|
||||
await page.getByText('Actions', { exact: true }).click();
|
||||
});
|
||||
|
||||
test('should update markdown code', async ({ page }) => {
|
||||
const markdown = page.locator('#markdown');
|
||||
const oldText = await markdown.inputValue();
|
||||
await typeInEditor(page, 'C --> HistoryTest', { bottom: true, newline: true });
|
||||
const newText = await markdown.inputValue();
|
||||
expect(newText).not.toBe(oldText);
|
||||
});
|
||||
|
||||
test.skip('should load gists from URL', async ({ page }) => {
|
||||
await page
|
||||
.locator('#gist')
|
||||
.fill('https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a');
|
||||
await page.getByText('Load Gist').click();
|
||||
await expect(page.getByText('Go shopping!!')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should download png and svg', async ({ page }) => {
|
||||
const downloadPNGPromise = verifyFileSizeGreaterThan(page, 'diagram', 'png', 29_000);
|
||||
await page.locator('#downloadPNG').click();
|
||||
await downloadPNGPromise;
|
||||
|
||||
const downloadSVGPromise = verifyFileSizeGreaterThan(page, 'diagram', 'svg', 10_000);
|
||||
await page.locator('#downloadSVG').click();
|
||||
await downloadSVGPromise;
|
||||
|
||||
// Verify downloaded file is different for different diagrams
|
||||
await page.getByText('Sample Diagrams').click();
|
||||
await page.getByText('ER', { exact: true }).click();
|
||||
|
||||
const downloadPNGPromise2 = verifyFileSizeGreaterThan(page, 'diagram', 'png', 35_000);
|
||||
await page.locator('#downloadPNG').click();
|
||||
await downloadPNGPromise2;
|
||||
|
||||
const downloadSVGPromise2 = verifyFileSizeGreaterThan(page, 'diagram', 'svg', 11_000);
|
||||
await page.locator('#downloadSVG').click();
|
||||
await downloadSVGPromise2;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { typeInEditor } from './utils';
|
||||
|
||||
test.describe('Auto sync tests', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page).toHaveURL(/.*\/edit#pako/);
|
||||
});
|
||||
|
||||
test('should dim diagram when code is edited', async ({ page }) => {
|
||||
await page.getByText('Auto sync').click();
|
||||
await expect(page.locator('#view')).not.toHaveClass(/outOfSync/);
|
||||
await expect(page.locator('#errorContainer')).not.toBeVisible();
|
||||
await typeInEditor(page, ' C --> Test', { bottom: true });
|
||||
await expect(page.locator('#view')).toHaveClass(/outOfSync/);
|
||||
await expect(page.locator('#errorContainer')).toContainText('Diagram out of sync.');
|
||||
const codeStore = await page.evaluate(() => localStorage.getItem('codeStore'));
|
||||
expect(codeStore).toBeTruthy();
|
||||
});
|
||||
|
||||
test.skip('should update diagram when shortcut is used', async ({ page }) => {
|
||||
await page.getByText('Auto sync').click();
|
||||
await expect(page.locator('#view')).not.toHaveClass(/outOfSync/);
|
||||
await typeInEditor(page, ' C --> Test');
|
||||
await expect(page.locator('#view')).toHaveClass(/outOfSync/);
|
||||
await expect(page.locator('#errorContainer')).toContainText('Diagram out of sync.');
|
||||
await page.locator('#editor').click();
|
||||
await page.keyboard.press('ControlOrMeta+Enter');
|
||||
await page.keyboard.press('ControlOrMeta+Enter');
|
||||
await expect(page.locator('#errorContainer')).not.toBeVisible();
|
||||
await expect(page.locator('#view')).not.toHaveClass(/outOfSync/);
|
||||
});
|
||||
|
||||
test('should show/hide sync button with auto sync', async ({ page }) => {
|
||||
await expect(page.locator('[data-cy=sync]')).not.toBeVisible();
|
||||
await page.getByText('Auto sync').click();
|
||||
await expect(page.locator('[data-cy=sync]')).toBeVisible();
|
||||
await page.locator('#autoSync').check();
|
||||
await expect(page.locator('[data-cy=sync]')).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('should not dim diagram when code is in sync', async ({ page }) => {
|
||||
await page.getByText('Auto sync').click();
|
||||
await expect(page.locator('#view')).not.toHaveClass(/outOfSync/);
|
||||
await typeInEditor(page, ' C --> Test');
|
||||
await expect(page.locator('#view')).toHaveClass(/outOfSync/);
|
||||
await page.locator('[data-cy=sync]').click();
|
||||
await expect(page.locator('#view')).not.toHaveClass(/outOfSync/);
|
||||
await page.locator('#autoSync').check();
|
||||
await typeInEditor(page, 'ing');
|
||||
await expect(page.locator('#view')).not.toHaveClass(/outOfSync/);
|
||||
const codeStore = await page.evaluate(() => localStorage.getItem('codeStore'));
|
||||
expect(codeStore).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Pan and Zoom', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('should toggle pan and zoom', async ({ page }) => {
|
||||
await expect(page.locator('#svg-pan-zoom-reset-pan-zoom')).not.toBeVisible();
|
||||
await page.getByText('Pan & Zoom').click();
|
||||
await expect(page.locator('#svg-pan-zoom-reset-pan-zoom')).toBeVisible();
|
||||
await page.getByText('Pan & Zoom').click();
|
||||
await expect(page.locator('#svg-pan-zoom-reset-pan-zoom')).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Editor docs tests', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/edit');
|
||||
await page.getByText('Sample Diagrams').click();
|
||||
});
|
||||
|
||||
test('Test default loading', async ({ page }) => {
|
||||
await expect(page.locator('[data-cy=docs][href^="https://mermaid.js.org/"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Test to see if the correct URL loads when changing from one diagram to other', async ({
|
||||
page
|
||||
}) => {
|
||||
await page.getByText('Flow', { exact: true }).click();
|
||||
await expect(page.locator('[data-cy=docs][href$="/syntax/flowchart.html"]')).toBeVisible();
|
||||
|
||||
await page.getByText('Config').click();
|
||||
await expect(
|
||||
page.locator('[data-cy=docs][href$="/syntax/flowchart.html#configuration"]')
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByText('Sequence').click();
|
||||
await expect(
|
||||
page.locator('[data-cy=docs][href$="/syntax/sequenceDiagram.html#configuration"]')
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByText('Code', { exact: true }).click();
|
||||
await expect(
|
||||
page.locator('[data-cy=docs][href$="/syntax/sequenceDiagram.html"]')
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("Test to check URLs for a case where config URL doesn't exist", async ({ page }) => {
|
||||
await page.getByText('State').click();
|
||||
await expect(page.locator('[data-cy=docs][href$="/syntax/stateDiagram.html"]')).toBeVisible();
|
||||
|
||||
await page.getByText('Config').click();
|
||||
await expect(page.locator('[data-cy=docs][href$="/syntax/stateDiagram.html"]')).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { typeInEditor } from './utils';
|
||||
|
||||
test.describe('Save History', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.addInitScript(() => {
|
||||
Object.defineProperty(Date, 'now', {
|
||||
value: () => new Date(2022, 0, 1).getTime()
|
||||
});
|
||||
});
|
||||
await page.goto('/edit');
|
||||
await page.getByText('History').click();
|
||||
});
|
||||
|
||||
test('should load history from localstorage', async ({ page }) => {
|
||||
await page.evaluate(() => {
|
||||
localStorage.setItem(
|
||||
'manualHistoryStore',
|
||||
'[{"state":{"code":"graph TD\\n A[Halloween] -->|Get money| B(Go shopping)","mermaid":"{\\n \\"theme\\": \\"dark\\"\\n}","autoSync":true,"updateDiagram":false},"time":0,"type":"manual","id":"d7ea820e-21dd-418a-b984-fd58acde09df","name":"hollow-art"},{"state":{"code":"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)","mermaid":"{\\n \\"theme\\": \\"dark\\"\\n}","autoSync":true,"updateDiagram":true},"time":0,"type":"manual","id":"b749ffc6-522b-4a44-86cf-7c1ffc3146b3","name":"helpful-ocean"}]'
|
||||
);
|
||||
localStorage.setItem(
|
||||
'autoHistoryStore',
|
||||
'[{"state":{"code":"graph TD\\n A[New Year] -->|Get money| B(Go shopping)","mermaid":"{\\n \\"theme\\": \\"dark\\"\\n}","autoSync":true,"updateDiagram":false},"time":0,"type":"auto","id":"69ea820e-522b-4a44-86cf-fd58acde09df","name":"barking-dog"},{"state":{"code":"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)","mermaid":"{\\n \\"theme\\": \\"dark\\"\\n}","autoSync":true,"updateDiagram":true},"time":0,"type":"manual","id":"x749ffc6-21dd-418a-b984-7c1ffc3146b3","name":"needy-mosquito"}]'
|
||||
);
|
||||
});
|
||||
await page.reload();
|
||||
await page.getByText('History').click();
|
||||
await expect(page.locator('#historyList li')).toHaveCount(2);
|
||||
await expect(page.locator('#historyList').getByText('No items in History')).not.toBeVisible();
|
||||
await expect(page.locator('#historyList')).toContainText('helpful-ocean');
|
||||
await expect(page.locator('#historyList')).toContainText('hollow-art');
|
||||
await page.getByText('Restore').first().click();
|
||||
await expect(page.locator('#view').getByText('Halloween')).toBeVisible();
|
||||
await page.getByText('Timeline').click();
|
||||
|
||||
await expect(page.locator('#historyList li')).toHaveCount(2);
|
||||
await expect(page.locator('#historyList').getByText('No items in History')).not.toBeVisible();
|
||||
await expect(page.locator('#historyList')).toContainText('needy-mosquito');
|
||||
await expect(page.locator('#historyList')).toContainText('barking-dog');
|
||||
await page.getByText('Restore').first().click();
|
||||
await expect(page.locator('#view').getByText('New Year')).toBeVisible();
|
||||
});
|
||||
|
||||
test.skip('should save when clicked', async ({ page }) => {
|
||||
await expect(page.locator('#historyList li')).toHaveCount(0);
|
||||
await expect(page.locator('#historyList')).toContainText('No items in History');
|
||||
await page.locator('#saveHistory').click();
|
||||
await expect(page.locator('#historyList').getByText('No items in History')).not.toBeVisible();
|
||||
await expect(page.locator('#historyList li')).toHaveCount(1);
|
||||
const dialogPromise = page.waitForEvent('dialog');
|
||||
await page.locator('#saveHistory').click();
|
||||
const dialog = await dialogPromise;
|
||||
expect(dialog.message()).toBe('State already saved.');
|
||||
await dialog.accept();
|
||||
|
||||
await typeInEditor(page, ' C --> HistoryTest');
|
||||
await page.locator('#saveHistory').click();
|
||||
await expect(page.locator('#historyList li')).toHaveCount(2);
|
||||
});
|
||||
|
||||
test.skip('should be able to restore and delete', async ({ page }) => {
|
||||
await page.locator('#saveHistory').click();
|
||||
await typeInEditor(page, ' C --> HistoryTest');
|
||||
await expect(page.locator('#historyList').getByText('No items in History')).not.toBeVisible();
|
||||
await expect(page.locator('#historyList li')).toHaveCount(1);
|
||||
await expect(page.locator('#view').getByText('HistoryTest')).toBeVisible();
|
||||
await page.getByText('Restore').click();
|
||||
await expect(page.locator('#view').getByText('HistoryTest')).not.toBeVisible();
|
||||
await page.getByText('Delete').click();
|
||||
await expect(page.locator('#historyList li')).toHaveCount(0);
|
||||
await expect(page.locator('#historyList')).toContainText('No items in History');
|
||||
await page.locator('#saveHistory').click();
|
||||
await typeInEditor(page, ' C --> HistoryTest');
|
||||
await page.locator('#saveHistory').click();
|
||||
await page.locator('#editor').type('ing');
|
||||
await page.locator('#clearHistory').click();
|
||||
|
||||
const dialog = await page.waitForEvent('dialog');
|
||||
expect(dialog.message()).toBe('Clear all saved items?');
|
||||
await dialog.accept();
|
||||
|
||||
await expect(page.locator('#historyList')).toContainText('No items in History');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Site Loads', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page).toHaveURL(/.*\/edit#pako/);
|
||||
});
|
||||
|
||||
test('Check Home page load', async ({ page }) => {
|
||||
await expect(page).toHaveURL(/.*\/edit/);
|
||||
await page.getByText('History').click();
|
||||
const codeStore = await page.evaluate(() => localStorage.getItem('codeStore'));
|
||||
expect(codeStore).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should keep code after reload', async ({ page }) => {
|
||||
await expect(page.locator('#editor')).toContainText('Car');
|
||||
await page.reload();
|
||||
await expect(page.locator('#editor')).toContainText('Car');
|
||||
});
|
||||
|
||||
test('Check Redirect from old URL', async ({ page }) => {
|
||||
await page.goto(
|
||||
'/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0NocmlzdG1hc10gLS0-fEdldCBtb25leXwgQihHbyBzaG9wcGluZylcbiAgICBCIC0tPiBDe0xldCBtZSB0aGlua31cbiAgICBDIC0tPnxPbmV8IERbTGFwdG9wXVxuICAgIEMgLS0-fFR3b3wgRVtpUGhvbmVdXG4gICAgQyAtLT58VGhyZWV8IEZbZmE6ZmEtY2FyIENhcl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ'
|
||||
);
|
||||
await expect(page).toHaveURL(/.*\/edit#pako:eNp/);
|
||||
});
|
||||
|
||||
test('should load sample diagrams when clicked', async ({ page }) => {
|
||||
await page.getByText('Sample Diagrams').click();
|
||||
await page.getByText('Pie').click();
|
||||
await expect(page.getByText('pie title Pets adopted by volunteers')).toBeVisible();
|
||||
await page.getByText('Class').click();
|
||||
await expect(page.getByText('classDiagram')).toBeVisible();
|
||||
});
|
||||
|
||||
test.describe('github', () => {
|
||||
test('should load diagram from gist', async ({ page }) => {
|
||||
await page.goto(
|
||||
`/edit?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a`
|
||||
);
|
||||
await page.getByText('History').click();
|
||||
await expect(page.locator('#view').getByText('Go shopping!!')).toBeVisible();
|
||||
await expect(page.getByText('Revisions')).toBeVisible();
|
||||
await expect(page.getByText('sidharthv96 v8f8f1e2')).toBeVisible();
|
||||
await expect(page.getByText('sidharthv96 v7851e19')).toBeVisible();
|
||||
const codeStore = await page.evaluate(() => localStorage.getItem('codeStore'));
|
||||
expect(codeStore).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should load diagram from gist revision', async ({ page }) => {
|
||||
await page.goto(
|
||||
'/edit?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/ec9b4ab0e41e4ff6287326cd3cb47affd7851e19'
|
||||
);
|
||||
await page.getByText('History').click();
|
||||
await expect(page.locator('#view').getByText('Party')).toBeVisible();
|
||||
await expect(page.getByText('Revisions')).toBeVisible();
|
||||
await expect(page.getByText('sidharthv96 v7851e19')).toBeVisible();
|
||||
const codeStore = await page.evaluate(() => localStorage.getItem('codeStore'));
|
||||
expect(codeStore).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should load diagram from raw files', async ({ page }) => {
|
||||
await page.goto(
|
||||
'/edit?code=https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/code.mmd&config=https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/config.json'
|
||||
);
|
||||
await expect(page.locator('#view').getByText('Party')).toBeVisible();
|
||||
const codeStore = await page.evaluate(() => localStorage.getItem('codeStore'));
|
||||
expect(codeStore).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test('should show troubleshooting steps if loading fails', async ({ page }) => {
|
||||
await page.goto('/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAg');
|
||||
await page.reload({ waitUntil: 'networkidle' });
|
||||
await expect(
|
||||
page.locator('#view').getByText('Please Click here to Raise an issue in github.')
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Verify types of URLs', () => {
|
||||
test('should load compressed URL', async ({ page }) => {
|
||||
await page.goto(
|
||||
'/edit#pako:eNpVkM2KwkAQhF-l6dMK5gVyEDRxvYi7sF6WjIcm0zqDzg_jBJEk725Hd2G3Tw31VVFUj23QjCWeEkUD-1p5kFs2O77BN1M6QFEshg1ncMHzfYDV2ybA1YQYrT_NXvhqgqDqtxPGkI315_ElVU__h-cB6mZLMYd4-Kvsb2GAdWM_jcT_V0xicb03RyqPVLSUoJI-OEfHyZHV0rqfDAqzYccKS3k1pbNC5Ufhuqgp81rbHBJKxuXKc6Quh6-7b7HMqeNfqLYkC7gfanwAlW1ZvQ'
|
||||
);
|
||||
await expect(page.locator('#view').getByText('New Year')).toBeVisible();
|
||||
await page.goto(
|
||||
'/edit#pako:eNptkU1PwzAMhv9K5BOI9Q9EXBDbJA477YYqITcxndV8QD40weh_Jy1rGR0-OY_tV2_sEyivCSQogzGuGduAtnaixINji0bcf1WVWGfVXdMtx8M1faYm4B8sxR27JLClJd6nwK4VLTlN4bI4jMQd2pLe3C4KFhNNcLQ92jv9ADGLNoTdozc-zIV4ZDsNlud7RtVN7_5Sb_jYrFcN3iN_0pPbEqUZK3QbTP_Ojyv4NdR4bwTHlyMbPcOQ3WJ2CliBpWCRdbnLqFJDOpClGmRJNYauhtr1pS-_6bKMjebkA8hXNJFWgDn5_YdTIFPINDWdb3vu6r8BaWOZRQ'
|
||||
);
|
||||
await expect(page.locator('#view').getByText('Animal')).toBeVisible();
|
||||
});
|
||||
|
||||
test.describe('Uncompressed URLs', () => {
|
||||
test('should load URL without specifier', async ({ page }) => {
|
||||
await page.goto(
|
||||
'/edit/#eyJjb2RlIjoiZ3JhcGhcbiAgICBUZXN0TGFiZWwiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ'
|
||||
);
|
||||
await expect(page.locator('#view').getByText('TestLabel')).toBeVisible();
|
||||
await page.goto(
|
||||
'/edit#eyJjb2RlIjoiY2xhc3NEaWFncmFtXG4gICAgQW5pbWFsIDx8LS0gRHVja1xuICAgIEFuaW1hbCA8fC0tIEZpc2hcbiAgICBBbmltYWwgPHwtLSBaZWJyYVxuICAgIEFuaW1hbCA6ICtpbnQgYWdlXG4gICAgQW5pbWFsIDogK1N0cmluZyBnZW5kZXJcbiAgICBBbmltYWw6ICtpc01hbW1hbCgpXG4gICAgQW5pbWFsOiArbWF0ZSgpXG4gICAgY2xhc3MgRHVja3tcbiAgICAgICtTdHJpbmcgYmVha0NvbG9yXG4gICAgICArc3dpbSgpXG4gICAgICArcXVhY2soKVxuICAgIH1cbiAgICBjbGFzcyBGaXNoe1xuICAgICAgLWludCBzaXplSW5GZWV0XG4gICAgICAtY2FuRWF0KClcbiAgICB9XG4gICAgY2xhc3MgWmVicmF7XG4gICAgICArYm9vbCBpc193aWxkXG4gICAgICArcnVuKClcbiAgICB9XG4gICAgICAgICAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGFya1wiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ'
|
||||
);
|
||||
await expect(page.locator('#view').getByText('Animal')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should load URL with "base64" specifier', async ({ page }) => {
|
||||
await page.goto(
|
||||
'/edit/#base64:eyJjb2RlIjoiZ3JhcGhcbiAgICBUZXN0TGFiZWwiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ'
|
||||
);
|
||||
await expect(page.locator('#view').getByText('TestLabel')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Test themes', () => {
|
||||
test.describe('Test color scheme preference', () => {
|
||||
test('should respect prefers-color-scheme light', async ({ page }) => {
|
||||
// Test light mode
|
||||
await page.emulateMedia({ colorScheme: 'light' });
|
||||
await page.goto('/edit');
|
||||
await expect(page.getByText('light').locator('..')).toHaveClass(/bordered/);
|
||||
await expect(page.getByText('dark').locator('..')).not.toHaveClass(/bordered/);
|
||||
});
|
||||
|
||||
test('should respect prefers-color-scheme dark', async ({ page }) => {
|
||||
// Test dark mode
|
||||
await page.emulateMedia({ colorScheme: 'dark' });
|
||||
await page.goto('/edit');
|
||||
await expect(page.getByText('dark').locator('..')).toHaveClass(/bordered/);
|
||||
await expect(page.getByText('light').locator('..')).not.toHaveClass(/bordered/);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Test light themes', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1440, height: 768 });
|
||||
await page.goto('/edit');
|
||||
await page.getByText('Theme').click();
|
||||
});
|
||||
|
||||
test('should set light theme as default', async ({ page }) => {
|
||||
await expect(page.getByText('light').locator('..')).toHaveClass(/bordered/);
|
||||
await expect(page.getByText('dark').locator('..')).not.toHaveClass(/bordered/);
|
||||
const themeStore = await page.evaluate(() => localStorage.getItem('themeStore'));
|
||||
expect(themeStore).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should change themes when clicked', async ({ page }) => {
|
||||
await expect(page.getByText('light').locator('..')).toHaveClass(/bordered/);
|
||||
await page.getByText('cupcake').click();
|
||||
await expect(page.getByText('cupcake').locator('..')).toHaveClass(/bordered/);
|
||||
await expect(page.getByText('light').locator('..')).not.toHaveClass(/bordered/);
|
||||
await expect(page.getByText('dark').locator('..')).not.toHaveClass(/bordered/);
|
||||
const themeStore = await page.evaluate(() => localStorage.getItem('themeStore'));
|
||||
expect(themeStore).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { type Page, expect } from '@playwright/test';
|
||||
import { readFileSync, statSync } from 'node:fs';
|
||||
|
||||
export const cmd = process.platform === 'darwin' ? 'Meta' : 'Control';
|
||||
|
||||
export interface EditorOptions {
|
||||
bottom?: boolean;
|
||||
newline?: boolean;
|
||||
}
|
||||
|
||||
interface WindowWithEditor {
|
||||
editorLoaded: boolean;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window extends WindowWithEditor {}
|
||||
}
|
||||
|
||||
export async function typeInEditor(
|
||||
page: Page,
|
||||
text: string,
|
||||
{ bottom = true, newline = false }: EditorOptions = {}
|
||||
) {
|
||||
await page.locator('#editor').click();
|
||||
const editor = page.locator('#editor');
|
||||
|
||||
if (bottom) {
|
||||
await editor.locator('textarea').press('PageDown');
|
||||
}
|
||||
if (newline) {
|
||||
await editor.locator('textarea').press('Enter');
|
||||
}
|
||||
await editor.locator('textarea').pressSequentially(text, { delay: 0 });
|
||||
}
|
||||
|
||||
export async function verifyFileSizeGreaterThan(
|
||||
page: Page,
|
||||
fileType: 'history' | 'diagram',
|
||||
extension: string,
|
||||
size: number
|
||||
) {
|
||||
const download = await page.waitForEvent('download');
|
||||
const path = await download.path();
|
||||
if (!path) throw new Error('Download path not available');
|
||||
const fileSize = statSync(path).size;
|
||||
expect(fileSize).toBeGreaterThan(size);
|
||||
expect(fileSize).toBeLessThan(size * 2);
|
||||
}
|
||||
|
||||
export async function verifyFileSnapshot(
|
||||
page: Page,
|
||||
fileType: 'history' | 'diagram',
|
||||
extension: string,
|
||||
content: string
|
||||
) {
|
||||
const download = await page.waitForEvent('download');
|
||||
const path = await download.path();
|
||||
if (!path) throw new Error('Download path not available');
|
||||
const fileContent = readFileSync(path, 'utf8');
|
||||
expect(fileContent).toContain(content);
|
||||
}
|
||||
+4
-2
@@ -7,13 +7,15 @@
|
||||
"cypress/**/*.js",
|
||||
"cypress/**/*.json",
|
||||
"static/**/*.js",
|
||||
"static/**/*.json"
|
||||
"static/**/*.json",
|
||||
"playwright.config.ts",
|
||||
"tests/**/*.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strictNullChecks": true,
|
||||
"types": ["vitest/importMeta"]
|
||||
"types": ["vitest/importMeta", "@playwright/test"]
|
||||
},
|
||||
"extends": "./.svelte-kit/tsconfig.json"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user