From 5fe3b566f05a1ce2afbf8a4d9c93baef2ed2bbec Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Tue, 24 Nov 2020 21:46:48 +0800 Subject: [PATCH] test: cases for PJAX --- __tests__/cases/pjax.commits-page.ts | 23 ++++++++++ __tests__/cases/pjax.files-page.ts | 23 ++++++++++ __tests__/cases/pjax.internal.ts | 29 ++++++++++++ __tests__/cases/pjax.mixed.ts | 30 +++++++++++++ __tests__/cases/project-page.gitako.ts | 8 ++-- __tests__/utils.ts | 61 ++++++++++++++++++++++++++ jest.config.js | 2 +- 7 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 __tests__/cases/pjax.commits-page.ts create mode 100644 __tests__/cases/pjax.files-page.ts create mode 100644 __tests__/cases/pjax.internal.ts create mode 100644 __tests__/cases/pjax.mixed.ts diff --git a/__tests__/cases/pjax.commits-page.ts b/__tests__/cases/pjax.commits-page.ts new file mode 100644 index 0000000..dde9484 --- /dev/null +++ b/__tests__/cases/pjax.commits-page.ts @@ -0,0 +1,23 @@ +import { expectToFind, expectToNotFind, sleep, waitForLegacyPJAXRedirect } from '../utils' + +describe(`in Gitako project page`, () => { + beforeAll(() => page.goto('https://github.com/EnixCoda/Gitako/commits/develop')) + + it('should not break go back in history', async () => { + for (let i = 0; i < 3; i++) { + const commitLinks = await page.$$( + `#js-repo-pjax-container .TimelineItem-body ol li > div:nth-child(1) a[href*="/commit/"]`, + ) + if (commitLinks.length < 2) throw new Error(`No enough commits`) + commitLinks[i].click() + await waitForLegacyPJAXRedirect() + await expectToFind('div.commit') + await sleep(1000) + + page.goBack() + await sleep(1000) + // The selector for file content + await expectToNotFind('div.commit') + } + }) +}) diff --git a/__tests__/cases/pjax.files-page.ts b/__tests__/cases/pjax.files-page.ts new file mode 100644 index 0000000..015236e --- /dev/null +++ b/__tests__/cases/pjax.files-page.ts @@ -0,0 +1,23 @@ +import { expectToFind, expectToNotFind, sleep, waitForLegacyPJAXRedirect } from '../utils' + +describe(`in Gitako project page`, () => { + beforeAll(() => page.goto('https://github.com/EnixCoda/Gitako/tree/develop/src')) + + it('should not break go back in history', async () => { + for (let i = 0; i < 3; i++) { + const commitLinks = await page.$$( + `.js-details-container div[role="row"] div[role="rowheader"] a[title*="."]`, + ) + if (commitLinks.length < 2) throw new Error(`No enough files`) + await commitLinks[i].click() + await waitForLegacyPJAXRedirect() + await expectToFind('table.js-file-line-container') + await sleep(1000) + + page.goBack() + await sleep(1000) + // The selector for file content + await expectToNotFind('table.js-file-line-container') + } + }) +}) diff --git a/__tests__/cases/pjax.internal.ts b/__tests__/cases/pjax.internal.ts new file mode 100644 index 0000000..c16412f --- /dev/null +++ b/__tests__/cases/pjax.internal.ts @@ -0,0 +1,29 @@ +import { + expectToFind, + expectToNotFind, + patientClick, + selectFileTreeItem, + sleep, + waitForPJAXAPIRedirect, +} from '../utils' + +describe(`in Gitako project page`, () => { + beforeAll(() => page.goto('https://github.com/EnixCoda/Gitako')) + + it('should work with PJAX', async () => { + await sleep(3000) + await patientClick(page, selectFileTreeItem('.babelrc')) + await waitForPJAXAPIRedirect() + + // The selector for file content + await expectToFind('table.js-file-line-container') + + page.goBack() + await waitForPJAXAPIRedirect() + + // The selector for file content + await expectToNotFind('table.js-file-line-container') + + // await waitForPJAXAPIRedirect() + }) +}) diff --git a/__tests__/cases/pjax.mixed.ts b/__tests__/cases/pjax.mixed.ts new file mode 100644 index 0000000..73912b3 --- /dev/null +++ b/__tests__/cases/pjax.mixed.ts @@ -0,0 +1,30 @@ +import { patientClick, selectFileTreeItem, sleep, waitForLegacyPJAXRedirect } from '../utils' + +describe(`in Gitako project page`, () => { + beforeAll(() => page.goto('https://github.com/EnixCoda/Gitako/src')) + + it('should work with PJAX', async () => { + await sleep(3000) + + await patientClick(page, selectFileTreeItem('src/analytics.ts')) + await waitForLegacyPJAXRedirect() + + await page.click('a[data-tab-item="issues-tab"]') + await waitForLegacyPJAXRedirect() + + await page.click('a[data-tab-item="pull-requests-tab"]') + await waitForLegacyPJAXRedirect() + + page.goBack() + await sleep(1000) + + page.goBack() + await sleep(1000) + + expect( + await page.evaluate( + () => document.querySelector('.final-path')?.textContent === 'analytics.ts', + ), + ).toBe(true) + }) +}) diff --git a/__tests__/cases/project-page.gitako.ts b/__tests__/cases/project-page.gitako.ts index 00deeaf..6df7c19 100644 --- a/__tests__/cases/project-page.gitako.ts +++ b/__tests__/cases/project-page.gitako.ts @@ -1,4 +1,4 @@ -import { expectToFind, expectToNotFind, scroll } from '../utils' +import { expectToFind, expectToNotFind, scroll, selectFileTreeItem } from '../utils' describe(`in Gitako project page`, () => { beforeAll(() => page.goto('https://github.com/EnixCoda/Gitako')) @@ -14,14 +14,14 @@ describe(`in Gitako project page`, () => { it('should render while scroll', async () => { const filesEle = await page.waitForSelector('.gitako-side-bar .files') // node of tsconfig.json should NOT be rendered before scroll down - await expectToNotFind('.gitako-side-bar .files a[title="tsconfig.json"]') + await expectToNotFind(selectFileTreeItem('tsconfig.json')) const box = await filesEle.boundingBox() if (box) { await page.mouse.move(box.x + 40, box.y + 40) - await scroll({ totalDistance: 100, duration: 5000 }) + await scroll({ totalDistance: 100, duration: 1000 }) // node of tsconfig.json should be rendered now - await expectToFind('.gitako-side-bar .files a[title="tsconfig.json"]') + await expectToFind(selectFileTreeItem('tsconfig.json')) } }) }) diff --git a/__tests__/utils.ts b/__tests__/utils.ts index 6bd566f..65b41c7 100644 --- a/__tests__/utils.ts +++ b/__tests__/utils.ts @@ -1,3 +1,5 @@ +import { Page } from 'puppeteer' + export async function expectToFind(selector: string) { await expect(page.waitForSelector(selector)).resolves.not.toBeNull() } @@ -25,3 +27,62 @@ export async function scroll({ await sleep((duration * step) / totalDistance) } } + +export function assert(condition: boolean, err?: Error | string) { + if (!condition) throw typeof err === 'string' ? new Error(err) : err +} + +let counter = 0 +export async function listenTo( + event: string, + target: 'document' | 'window', + callback: (...args: Args) => void, + oneTime?: boolean, +) { + const callbackName = 'onEvent' + ++counter + await page.exposeFunction(callbackName, callback) + await page.evaluate( + (event, target, callbackName, oneTime) => { + const t = target === 'document' ? document : window + const onEvent = (...args: any[]): void => { + ;((window[callbackName as any] as any) as (...args: any[]) => void)(...args) + if (oneTime) t.removeEventListener(event, onEvent) + } + t.addEventListener(event, onEvent) + }, + event, + target, + callbackName, + oneTime || false, + ) +} + +export function once(event: string, target: 'document' | 'window') { + return new Promise(resolve => { + listenTo( + event, + target, + (...args) => { + resolve(args) + }, + true, + ) + }) +} + +export function waitForLegacyPJAXRedirect() { + return once('pjax:end', 'document') +} + +export function waitForPJAXAPIRedirect() { + return once('pjax:ready', 'document') +} + +export function selectFileTreeItem(path: string): string { + return `.gitako-side-bar .files a[title="${path}"]` +} + +export async function patientClick(page: Page, selector: string) { + await page.waitForSelector(selector) + await page.click(selector) +} diff --git a/jest.config.js b/jest.config.js index 8967fa4..eafe22d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -61,7 +61,7 @@ module.exports = { // globals: {}, // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", + maxWorkers: 1, // more than 1 workers may make tabs in background and never renders Gitako's file items. // An array of directory names to be searched recursively up from the requiring module's location // moduleDirectories: [