Skip to content

Commit

Permalink
add basic E2E test (#958)
Browse files Browse the repository at this point in the history
* set E2E test environment & make basic home page test

* test e2e test applied deployment

* add puppeteer orbs

* revert deployment script

* add click with capture helper method

* Add home mobile layout e2e test

* Fixed title contains wrong text

* Add paper show e2e test script

* WIP - e2e script

* fix mobile sign in test

* change waitFor option to natural option

* change waitFor logic to real world waiting
  • Loading branch information
TylerShin committed Aug 16, 2019
1 parent a79c4d4 commit 79e73f3
Show file tree
Hide file tree
Showing 15 changed files with 928 additions and 19 deletions.
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ jobs:
TZ: "Asia/Seoul"
steps:
- checkout
- run:
name: Set up puppeteer
command: 'sh .circleci/setup_puppeteer.sh'
- run:
name: updating npm...
command: npmv=$(echo $(npm -v) | head -c 1); if [ "$npmv" -lt "6" ]; then sudo npm i -g npm; else echo "Node.js Docker Team finally decided to include npm v6+ in latest image; you can remove this script now"; fi
Expand Down
8 changes: 8 additions & 0 deletions .circleci/setup_puppeteer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

sudo apt-get update
sudo apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget --fix-missing
2 changes: 1 addition & 1 deletion app/components/paperShow/helmet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const PaperShowHelmet: React.FC<{ paper: Paper }> = React.memo(({ paper }) => {

return (
<Helmet>
<title>{`${metaTitleContent} | Scinapse | Academic search engine for paper}`}</title>
<title>{`${metaTitleContent} | Scinapse | Academic search engine for paper`}</title>
<link rel="canonical" href={`https://scinapse.io/papers/${paper.id}`} />
<meta itemProp="name" content={`${metaTitleContent} | Scinapse | Academic search engine for paper`} />
<meta name="description" content={buildPageDescription(paper)} />
Expand Down
1 change: 1 addition & 0 deletions e2eTest/constants/setting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const DEFAULT_SCREEN_SHOT_OUTPUT_DIRECTORY = './output/screenshots';
35 changes: 35 additions & 0 deletions e2eTest/helpers/clickWithCapture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ClickOptions, Page } from 'puppeteer';
import { DEFAULT_SCREEN_SHOT_OUTPUT_DIRECTORY } from '../constants/setting';

/*****************************************************************************
*****************************************************************************
# Filename Convention
---
[test_name]-[test_case_name]-[action_name]
ex)
[desktop_home_page]-[search_feature]-[click_search_icon]
*****************************************************************************
*****************************************************************************/

interface ClickWithCaptureParams {
page: Page;
testName: string;
caseName: string;
actionName: string;
selector: string;
options?: ClickOptions;
}
export default async function clickWithCapture(params: ClickWithCaptureParams) {
const { page, testName, caseName, actionName, selector, options } = params;

const prefix = `${DEFAULT_SCREEN_SHOT_OUTPUT_DIRECTORY}/[${testName.replace(' ', '-')}]-[${caseName.replace(
' ',
'-'
)}]-[${actionName.replace(' ', '-')}]`;

await page.screenshot({ path: `${prefix}-before.png` });
await page.click(selector, options);
await page.screenshot({ path: `${prefix}-after.png` });
}
6 changes: 6 additions & 0 deletions e2eTest/helpers/getHost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default function getHost() {
if (process.env.STAGE === 'stage') {
return 'stage.scinapse.io';
}
return 'scinapse.io';
}
72 changes: 72 additions & 0 deletions e2eTest/home_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import getHost from './helpers/getHost';
import clickWithCapture from './helpers/clickWithCapture';

const DESKTOP_TEST_NAME = 'desktop Home page test';
const MOBILE_TEST_NAME = 'mobile Home page test';

function homeE2E(TEST_NAME: string, width: number, height: number) {
describe(TEST_NAME, () => {
beforeAll(async () => {
await page.setViewport({ width, height });
await page.goto(`https://${getHost()}`, { waitUntil: 'networkidle0' });
});

afterAll(async () => {
// TODO: Change below 'as any' after type definition package being updated
// follow https://github.com/DefinitelyTyped/DefinitelyTyped/pull/37390
await (jestPuppeteer as any).resetBrowser();
});

describe('when enter the page', () => {
it('should render proper title', async () => {
await expect(page.title()).resolves.toMatch('Scinapse | Academic search engine for paper');
});

it('should render the search input element', async () => {
await expect(page.$("input[class^='improvedHome_searchInput']")).resolves.not.toBeNull();
});
});

describe('when user use search feature', () => {
beforeEach(async () => {
await page.click("input[class^='improvedHome_searchInput']", { clickCount: 3 });
await page.type("input[class^='improvedHome_searchInput']", 'machine learning');
});

afterEach(async () => {
await page.goBack();
});

describe('when user click the search icon', () => {
it('should show the search result page', async () => {
await Promise.all([
page.waitForSelector("[class^='searchList_searchItems']", { timeout: 30000 }),
clickWithCapture({
page,
testName: TEST_NAME,
caseName: 'user use search feature',
actionName: 'click search icon',
selector: "[class^='searchQueryInput_searchButton']",
}),
]);

await expect(page.$("[class^='searchList_searchItems']")).resolves.not.toBeNull();
});
});

describe('when user press the enter key', () => {
it('should show the search result page', async () => {
await Promise.all([
page.waitForSelector("[class^='searchList_searchItems']", { timeout: 30000 }),
page.keyboard.press('Enter'),
]);

await expect(page.$("[class^='searchList_searchItems']")).resolves.not.toBeNull();
});
});
});
});
}

homeE2E(DESKTOP_TEST_NAME, 1920, 1080);
homeE2E(MOBILE_TEST_NAME, 320, 568);
8 changes: 8 additions & 0 deletions e2eTest/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const mkdirp = require('mkdirp');
const { DEFAULT_SCREEN_SHOT_OUTPUT_DIRECTORY } = require('./constants/setting');

mkdirp(DEFAULT_SCREEN_SHOT_OUTPUT_DIRECTORY, function (err) {
if (err) console.error(err)
});

jest.setTimeout(30000);
68 changes: 68 additions & 0 deletions e2eTest/paperShow_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import getHost from './helpers/getHost';
import clickWithCapture from './helpers/clickWithCapture';

const DESKTOP_TEST_NAME = 'desktop paper show page test';
const MOBILE_TEST_NAME = 'mobile paper show page test';

function paperShowE2E(TEST_NAME: string, width: number, height: number) {
describe(TEST_NAME, () => {
beforeAll(async () => {
await page.setViewport({ width, height });
await page.goto(`https://${getHost()}/papers/2559394418`, { waitUntil: 'networkidle0' });
});

describe('when enter the page', () => {
it('should render proper title', async () => {
await expect(page.title()).resolves.toMatch(
'[PDF] Quantum Machine Learning | Scinapse | Academic search engine for paper'
);
});

it('should render the search input element', async () => {
await expect(page.$("input[class^='improvedHeader_searchInput']")).resolves.not.toBeNull();
});
});

describe('when user use search feature', () => {
beforeEach(async () => {
await page.click("input[class^='improvedHeader_searchInput']", { clickCount: 3 });
await page.type("input[class^='improvedHeader_searchInput']", 'cern');
});

afterEach(async () => {
await page.goBack();
});

describe('when user click the search icon', () => {
it('should show the search result page', async () => {
await Promise.all([
page.waitForSelector("[class^='searchList_searchItems']", { timeout: 30000 }),
clickWithCapture({
page,
testName: TEST_NAME,
caseName: 'user use search feature',
actionName: 'click search icon',
selector: "[class^='searchQueryInput_searchIconButton']",
}),
]);

await expect(page.$("[class^='searchList_searchItems']")).resolves.not.toBeNull();
});
});

describe('when user press the enter key', () => {
it('should show the search result page', async () => {
await Promise.all([
page.waitForSelector("[class^='searchList_searchItems']", { timeout: 30000 }),
page.keyboard.press('Enter'),
]);

await expect(page.$("[class^='searchList_searchItems']")).resolves.not.toBeNull();
});
});
});
});
}

paperShowE2E(DESKTOP_TEST_NAME, 1920, 1080);
paperShowE2E(MOBILE_TEST_NAME, 320, 568);
67 changes: 67 additions & 0 deletions e2eTest/searchResult_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import getHost from './helpers/getHost';
import clickWithCapture from './helpers/clickWithCapture';

const DESKTOP_TEST_NAME = 'desktop search result page test';
const MOBILE_TEST_NAME = 'mobile search result page test';

function searchResultE2E(TEST_NAME: string, width: number, height: number) {
describe(TEST_NAME, () => {
beforeAll(async () => {
await page.setViewport({ width, height });
await page.goto(`https://${getHost()}/search?query=machine%20learning`, { waitUntil: 'networkidle0' });
});

describe('when enter the page', () => {
it('should render proper title', async () => {
await expect(page.title()).resolves.toMatch('machine learning | Scinapse | Academic search engine for paper');
});

it('should render proper search result', async () => {
await expect(page.$("[class^='searchList_searchItems']")).resolves.not.toBeNull();
});

it('should render proper header', async () => {
await expect(page.$("[class^='improvedHeader_headerContainer']")).resolves.not.toBeNull();
});
});

describe('when user use search feature', () => {
beforeEach(async () => {
await page.click("input[class^='improvedHeader_searchInput']", { clickCount: 3 });
await page.type("input[class^='improvedHeader_searchInput']", 'cern');
});

afterEach(async () => {
await page.goBack();
});

describe('when user click the search icon', () => {
it('should show the search result page', async () => {
await Promise.all([
page.waitFor(3000),
clickWithCapture({
page,
testName: TEST_NAME,
caseName: 'user use search feature',
actionName: 'click search icon',
selector: "[class^='searchQueryInput_searchIconButton']",
}),
]);

await expect(page.$("[class^='searchList_searchItems']")).resolves.not.toBeNull();
});
});

describe('when user press the enter key', () => {
it('should show the search result page', async () => {
await Promise.all([page.waitFor(10000), page.keyboard.press('Enter')]);

await expect(page.$("[class^='searchList_searchItems']")).resolves.not.toBeNull();
});
});
});
});
}

searchResultE2E(DESKTOP_TEST_NAME, 1920, 1080);
searchResultE2E(MOBILE_TEST_NAME, 320, 568);
Loading

0 comments on commit 79e73f3

Please sign in to comment.