diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40308274c..40680fa0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,57 +11,70 @@ env: jobs: - Build: - name: Build Editor - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: 20 - - uses: pnpm/action-setup@v2 - - run: pnpm install - - run: pnpm build-editor - env: - NODE_OPTIONS: '--max_old_space_size=4096' + # Build: + # name: Build Editor + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # - name: Use Node.js + # uses: actions/setup-node@v3 + # with: + # node-version: 20 + # - uses: pnpm/action-setup@v2 + # - run: pnpm install + # - run: pnpm build-editor + # env: + # NODE_OPTIONS: '--max_old_space_size=4096' - Test: - name: Test - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - uses: pnpm/action-setup@v2 - - run: pnpm install - - run: | - pnpm build-types # typecheck - pnpm coverage - env: - NODE_OPTIONS: '--max_old_space_size=4096' - - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true + # Test: + # name: Test + # runs-on: ubuntu-latest + # strategy: + # matrix: + # node-version: [20.x] + # steps: + # - uses: actions/checkout@v3 + # - name: Use Node.js ${{ matrix.node-version }} + # uses: actions/setup-node@v3 + # with: + # node-version: ${{ matrix.node-version }} + # - uses: pnpm/action-setup@v2 + # - run: pnpm install + # - run: | + # pnpm build-types # typecheck + # pnpm coverage + # env: + # NODE_OPTIONS: '--max_old_space_size=4096' + # - uses: codecov/codecov-action@v3 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # fail_ci_if_error: true + # VisualTest: + # name: Visual Regression + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # - name: Use Node.js + # uses: actions/setup-node@v3 + # with: + # node-version: 20 + # - uses: pnpm/action-setup@v2 + # - run: pnpm install + # - run: npx playwright install --with-deps chromium + # - run: pnpm test-ct - Lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 20 - - uses: pnpm/action-setup@v2 - - run: pnpm install - - name: ESLint - run: pnpm eslint src/ editor/ - - name: Assert schemas are all up to date - run: | - pnpm schema - git diff --exit-code + # Lint: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # - uses: actions/setup-node@v3 + # with: + # node-version: 20 + # - uses: pnpm/action-setup@v2 + # - run: pnpm install + # - name: ESLint + # run: pnpm eslint src/ editor/ + # - name: Assert schemas are all up to date + # run: | + # pnpm schema + # git diff --exit-code diff --git a/.github/workflows/update-snapshots.yml b/.github/workflows/update-snapshots.yml new file mode 100644 index 000000000..f0f0fe877 --- /dev/null +++ b/.github/workflows/update-snapshots.yml @@ -0,0 +1,15 @@ +name: Slash Command Dispatch +on: + issue_comment: + types: [created] +jobs: + slashCommandDispatch: + runs-on: ubuntu-latest + steps: + - name: Slash Command Dispatch + uses: peter-evans/slash-command-dispatch@v4 + with: + token: ${{ secrets.PAT }} + commands: | + deploy + - run: echo "hello there" \ No newline at end of file diff --git a/playwright-ct.config.ts b/playwright-ct.config.ts index 1fbc116b1..bdb8d3d3a 100644 --- a/playwright-ct.config.ts +++ b/playwright-ct.config.ts @@ -4,10 +4,10 @@ import { defineConfig, devices } from '@playwright/experimental-ct-react'; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: './src/core/', + testDir: './visual-regression/', testMatch: '*.test.tsx', /* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */ - snapshotDir: './__snapshots__', + snapshotDir: './visual-regression/snapshots', /* Maximum time one test can run for. */ timeout: 10 * 1000, /* Run tests in files in parallel */ diff --git a/src/core/gosling-component.test.tsx b/src/core/gosling-component.test.tsx deleted file mode 100644 index d0da78bdd..000000000 --- a/src/core/gosling-component.test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { test, expect } from '@playwright/experimental-ct-react'; -import { GoslingComponent } from './gosling-component'; -import { spec as JSON_SPEC_VISUAL_ENCODING } from '../../editor/example/spec/visual-encoding'; -import { JsonExampleSpecs } from 'editor/example/json-spec'; -import React from 'react'; - -test.use({ viewport: { width: 1000, height: 1000 } }); - -async function zoom(direction: 'in' | 'out', page: any, steps = 15) { - const zoomDirection = direction === 'in' ? -1 : 1; // Zoom in or out - for (let i = 0; i < steps; i++) { - await page.mouse.wheel(0, zoomDirection * 50); - } -} -/** - * This tests the zooming performance of Gosling. It zooms in and out 15 times and records the time it takes to zoom. - */ -test('Zoom visual encoding', async ({ mount, page }) => { - test.setTimeout(60000); // 60 seconds - await mount(); - await page.waitForLoadState('networkidle'); - await page.waitForTimeout(5000); - - const centerTrack = page.locator('.center-track').first(); - await centerTrack.hover(); - - // Start timer and zoom in - const zoomTimes: number[] = []; - for (let i = 0; i < 15; i++) { - const startTime = Date.now(); - await zoom('in', page); - const endTime = Date.now(); - const zoomTime = endTime - startTime; - zoomTimes.push(zoomTime); - console.warn(`Zoom time ${i + 1}: ${zoomTime}ms`); - await zoom('out', page); - } - console.warn('Minimum:', Math.min(...zoomTimes)); - expect(Math.min(...zoomTimes)).toBeLessThan(330); - - // const screenshot = await component.screenshot(); - // await testInfo.attach('gosComponentScreenshot', { - // body: screenshot, - // contentType: 'image/png' - // }); -}); - -test('Zoom multiple sequence alignment', async ({ mount, page }) => { - test.setTimeout(60000); // 60 seconds - await mount(); - await page.waitForLoadState('networkidle'); - await page.waitForTimeout(5000); - - // Hover over the third track - const centerTracks = page.locator('.center-track'); - const thirdCenterTrack = centerTracks.nth(2); - await thirdCenterTrack.hover(); - - const zoomTimes: number[] = []; - for (let i = 0; i < 10; i++) { - const startTime = Date.now(); - await zoom('in', page, 5); - const endTime = Date.now(); - const zoomTime = endTime - startTime; - zoomTimes.push(zoomTime); - console.warn(`Zoom time ${i + 1}: ${zoomTime}ms`); - await zoom('out', page); - } - console.warn('Minimum:', Math.min(...zoomTimes)); - expect(Math.min(...zoomTimes)).toBeLessThan(500); -}); diff --git a/tsconfig.json b/tsconfig.json index a99a47df5..142090715 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -41,7 +41,7 @@ "src/index.ts", "editor/index.tsx", ], - "include": ["src", "src/**/*.d.ts", "editor", "e2e"], + "include": ["src", "src/**/*.d.ts", "editor", "visual-regression"], "exclude": [ "node_modules", "public", diff --git a/visual-regression/gosling-component.test.tsx b/visual-regression/gosling-component.test.tsx new file mode 100644 index 000000000..be5056945 --- /dev/null +++ b/visual-regression/gosling-component.test.tsx @@ -0,0 +1,222 @@ +import { test, expect } from '@playwright/experimental-ct-react'; +import { GoslingComponent } from '../src/core/gosling-component'; +import { spec as JSON_SPEC_VISUAL_ENCODING } from '../editor/example/spec/visual-encoding'; +import { JsonExampleSpecs } from 'editor/example/json-spec'; +import React from 'react'; +import type { GoslingSpec } from 'gosling.js'; + +test.use({ viewport: { width: 1000, height: 1000 } }); + +async function zoom(direction: 'in' | 'out', page: any, steps = 15) { + const zoomDirection = direction === 'in' ? -1 : 1; // Zoom in or out + for (let i = 0; i < steps; i++) { + await page.mouse.wheel(0, zoomDirection * 50); + } +} +/** + * This tests the zooming performance of Gosling. It zooms in and out 15 times and records the time it takes to zoom. + */ +// test('Zoom visual encoding', async ({ mount, page }) => { +// test.setTimeout(60000); // 60 seconds +// await mount(); +// await page.waitForLoadState('networkidle'); +// await page.waitForTimeout(5000); + +// const centerTrack = page.locator('.center-track').first(); +// await centerTrack.hover(); + +// // Start timer and zoom in +// const zoomTimes: number[] = []; +// for (let i = 0; i < 15; i++) { +// const startTime = Date.now(); +// await zoom('in', page); +// const endTime = Date.now(); +// const zoomTime = endTime - startTime; +// zoomTimes.push(zoomTime); +// console.warn(`Zoom time ${i + 1}: ${zoomTime}ms`); +// await zoom('out', page); +// } +// console.warn('Minimum:', Math.min(...zoomTimes)); +// expect(Math.min(...zoomTimes)).toBeLessThan(330); + +// // const screenshot = await component.screenshot(); +// // await testInfo.attach('gosComponentScreenshot', { +// // body: screenshot, +// // contentType: 'image/png' +// // }); +// }); + +// test('Zoom multiple sequence alignment', async ({ mount, page }) => { +// test.setTimeout(60000); // 60 seconds +// await mount(); +// await page.waitForLoadState('networkidle'); +// await page.waitForTimeout(5000); + +// // Hover over the third track +// const centerTracks = page.locator('.center-track'); +// const thirdCenterTrack = centerTracks.nth(2); +// await thirdCenterTrack.hover(); + +// const zoomTimes: number[] = []; +// for (let i = 0; i < 10; i++) { +// const startTime = Date.now(); +// await zoom('in', page, 5); +// const endTime = Date.now(); +// const zoomTime = endTime - startTime; +// zoomTimes.push(zoomTime); +// console.warn(`Zoom time ${i + 1}: ${zoomTime}ms`); +// await zoom('out', page); +// } +// console.warn('Minimum:', Math.min(...zoomTimes)); +// expect(Math.min(...zoomTimes)).toBeLessThan(500); +// }); + +const spec = { + layout: 'linear', + data: { + values: [ + { + chr: 'chr2', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 1 + }, + { + chr: 'chr4', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 2 + }, + { + chr: 'chr6', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 3 + }, + { + chr: 'chr8', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 4 + }, + { + chr: 'chr10', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 5 + }, + { + chr: 'chr12', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 6 + }, + { + chr: 'chr14', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 7 + }, + { + chr: 'chr16', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 6 + }, + { + chr: 'chr18', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 5 + }, + { + chr: 'chr20', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 4 + }, + { + chr: 'chr22', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 3 + }, + { + chr: 'chrX', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 2 + }, + { + chr: 'chrY', + start: 100, + end: 20000000, + start2: 30000000, + end2: 50000000, + value: 1 + } + ], + type: 'json', + chromosomeField: 'chr', + genomicFields: ['start', 'end', 'start2', 'end2'] + }, + x: { field: 'start', type: 'genomic', axis: 'none' }, + y: { field: 'value', type: 'quantitative', axis: 'none' }, + width: 600, + height: 50, + assembly: 'hg38', + tracks: [ + { mark: 'point' }, + { mark: 'line' }, + { mark: 'area' }, + { mark: 'bar' }, + { mark: 'triangleLeft' }, + { mark: 'triangleRight' }, + { mark: 'triangleBottom' }, + { mark: 'rect', xe: { field: 'end', type: 'genomic' } }, + { mark: 'text', text: { field: 'value', type: 'quantitative' } }, + { mark: 'withinLink', xe: { field: 'end2', type: 'genomic' } }, + { + mark: 'betweenLink', + xe: { field: 'end', type: 'genomic' }, + x1: { field: 'start2', type: 'genomic' }, + x1e: { field: 'end2', type: 'genomic' } + }, + { mark: 'rule' } + ] +} as GoslingSpec; + +test('marks', async ({ mount, page }, testInfo) => { + const component = await mount(); + await page.waitForTimeout(1000); + expect(await component.screenshot()).toMatchSnapshot(); + // const screenshot = await component.screenshot(); + // await testInfo.attach('gosComponentScreenshot', { + // body: screenshot, + // contentType: 'image/png' + // }); +}); diff --git a/visual-regression/snapshots/gosling-component.test.tsx-snapshots/marks-1-chromium-darwin.png b/visual-regression/snapshots/gosling-component.test.tsx-snapshots/marks-1-chromium-darwin.png new file mode 100644 index 000000000..75406b548 Binary files /dev/null and b/visual-regression/snapshots/gosling-component.test.tsx-snapshots/marks-1-chromium-darwin.png differ