Skip to content

Commit 24660b8

Browse files
test(cypress): Add end-to-end test infrastructure and base cases (#543)
* test(cypress): Add end-to-end test infrastructure and base cases * test(cypress): Update test script to better handle edge cases Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 783d57c commit 24660b8

File tree

13 files changed

+309
-52
lines changed

13 files changed

+309
-52
lines changed

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ jobs:
2222
script: yarn lint
2323
- name: 'Unit Tests'
2424
script: yarn test
25+
- name: 'E2E Tests'
26+
if: fork = false # Note: We can only run E2E tests on canonical due to security concerns
27+
script: yarn test:e2e
2528
notifications:
2629
email:
2730
recipients:
28-
- preview-alerts@box.com
31+
- preview-dev@box.com

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"babel-plugin-istanbul": "^6.0.0",
6868
"babel-plugin-react-intl": "^7.5.1",
6969
"babel-plugin-transform-require-ignore": "^0.1.1",
70+
"box-node-sdk": "^1.33.0",
7071
"circular-dependency-plugin": "^5.2.0",
7172
"conventional-github-releaser": "^3.1.3",
7273
"core-js": "^3.6.5",
@@ -140,8 +141,8 @@
140141
"start:dev": "yarn setup && LANGUAGE=en-US BABEL_ENV=dev NODE_ENV=dev yarn webpack-dev-server --config scripts/webpack.config.js --mode development",
141142
"start:linked": "IS_LINKED=1 yarn start",
142143
"test": "BABEL_ENV=test NODE_ENV=test yarn jest",
143-
"test:e2e": "npm-run-all -p -r start:dev cy:run",
144-
"test:e2e:open": "npm-run-all -p -r start:dev cy:open",
144+
"test:e2e": "node scripts/cypress.js",
145+
"test:e2e:open": "node scripts/cypress.js -o",
145146
"test:watch": "yarn test --watch"
146147
},
147148
"husky": {

scripts/cypress.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* eslint-disable no-console */
2+
const BoxSDK = require('box-node-sdk');
3+
const childProcess = require('child_process');
4+
5+
const { argv, env } = process;
6+
const { E2E_ACCESS_TOKEN, E2E_CLIENT_ID } = env;
7+
const KILL_SIGNALS = [
8+
'SIGABRT',
9+
'SIGBUS',
10+
'SIGFPE',
11+
'SIGHUP',
12+
'SIGILL',
13+
'SIGINT',
14+
'SIGQUIT',
15+
'SIGSEGV',
16+
'SIGTERM',
17+
'SIGTRAP',
18+
'SIGUSR1',
19+
'SIGUSR2',
20+
];
21+
22+
if (!E2E_ACCESS_TOKEN) {
23+
throw new Error('E2E_ACCESS_TOKEN must be set as an environment variable');
24+
}
25+
26+
if (!E2E_CLIENT_ID) {
27+
throw new Error('E2E_CLIENT_ID must be set as an environment variable');
28+
}
29+
30+
const sdk = new BoxSDK({
31+
clientID: E2E_CLIENT_ID,
32+
clientSecret: 'none',
33+
});
34+
35+
const client = sdk.getBasicClient(E2E_ACCESS_TOKEN);
36+
37+
async function cleanup(folderId) {
38+
console.log('Cleanup test folder and files...');
39+
40+
try {
41+
await client.folders.delete(folderId, { recursive: true });
42+
console.log('Cleanup complete.');
43+
} catch (error) {
44+
console.error(`Cleanup failed. Error: ${error.message}`);
45+
}
46+
}
47+
48+
async function main() {
49+
const testFolderName = `Test ${new Date().toISOString()}`;
50+
51+
// Bootstrap the test folder and copy template files into it
52+
console.log(`Setup test folder: ${testFolderName}...`);
53+
const { id: folderId } = await client.folders.create('118537970832', testFolderName); // Test folder
54+
const { id: documentId } = await client.files.copy('694470903390', folderId); // Document template
55+
const { id: imageId } = await client.files.copy('694468799644', folderId); // Image template
56+
console.log('Setup complete.');
57+
58+
// Attempt to cleanup test folder before script is killed (example: CTL+C)
59+
KILL_SIGNALS.forEach(signal => process.on(signal, () => cleanup(folderId)));
60+
61+
try {
62+
console.log('Cypress run starting...');
63+
64+
const suffix = argv.indexOf('-o') >= 0 ? 'open' : 'run'; // Pass -o to run Cypress in "open" mode
65+
const output = childProcess.execSync(`yarn npm-run-all -p -r start:dev cy:${suffix}`, {
66+
env: {
67+
...env,
68+
CYPRESS_ACCESS_TOKEN: E2E_ACCESS_TOKEN,
69+
CYPRESS_FILE_ID_DOC: documentId,
70+
CYPRESS_FILE_ID_IMAGE: imageId,
71+
},
72+
});
73+
74+
console.log('Cypress run SUCCESS. Output:');
75+
console.log('------------------------------');
76+
console.log(output.toString());
77+
} catch (error) {
78+
console.log('Cypress run FAILURE. Output:');
79+
console.log('------------------------------');
80+
console.log(error.stdout.toString());
81+
process.exitCode = error && error.status ? error.status : 0;
82+
}
83+
84+
await cleanup(folderId);
85+
86+
console.log('Test script complete. Exiting.');
87+
}
88+
89+
main();

scripts/release.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ reset_to_master() {
7272

7373
build_lint_and_test() {
7474
# The build command includes linting
75-
yarn build && yarn test || return 1
75+
yarn build && yarn test && yarn test:e2e || return 1
7676
}
7777

7878

test/index.html

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
<meta name="viewport" content="width=device-width" />
44
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
55
<link rel="stylesheet" href="./styles.css" />
6-
<link rel="stylesheet" href="https://cdn01.boxcdn.net/platform/preview/2.32.1/en-US/preview.css" />
6+
<link rel="stylesheet" href="https://cdn01.boxcdn.net/platform/preview/2.47.0/en-US/preview.css" />
77
<link rel="stylesheet" href="./annotations.css" />
88
<script src="https://cdn01.boxcdn.net/polyfills/core-js/2.5.3/core.min.js"></script>
9-
<script src="https://cdn01.boxcdn.net/platform/preview/2.32.1/en-US/preview.js"></script>
9+
<script src="https://cdn01.boxcdn.net/platform/preview/2.47.0/en-US/preview.js"></script>
1010
<script src="./annotations.js"></script>
1111
</head>
1212

@@ -55,27 +55,17 @@
5555
return;
5656
}
5757

58-
// Load Preview + Annotations with the passed in file ID
59-
var options = {
60-
Image: {
61-
enabledTypes: ['point'],
62-
},
63-
Document: {
64-
enabledTypes: ['draw', 'point', 'highlight-comment', 'highlight'],
65-
},
66-
Presentation: {
67-
enabledTypes: ['draw', 'point', 'highlight-comment', 'highlight'],
68-
},
69-
};
70-
7158
/* global BoxAnnotations */
72-
var annotations = new BoxAnnotations(options);
59+
var annotations = new BoxAnnotations();
7360

7461
/* global Box */
7562
var preview = new Box.Preview();
63+
7664
preview.show(fileid, token, {
7765
container: '.preview-container',
7866
boxAnnotations: annotations,
67+
showAnnotations: true,
68+
showAnnotationsControls: true,
7969
});
8070
}
8171

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// <reference types="Cypress" />
2+
describe('Regions', () => {
3+
beforeEach(() => {
4+
cy.visit('/');
5+
});
6+
7+
it('should create a new region on a document', () => {
8+
// Show the preview
9+
cy.showPreview(Cypress.env('FILE_ID_DOC'));
10+
11+
// Wait for the empty region layer to be present
12+
cy.getByTestId('ba-Layer--region');
13+
14+
// Assert that the region creator does not exist and no annotations are present
15+
cy.getByTestId('ba-RegionCreator').should('not.exist');
16+
cy.get('[data-testid^="ba-AnnotationTarget"]').should('not.exist');
17+
18+
// Enter region creation mode
19+
cy.getByTestId('bp-AnnotationsControls-regionBtn').click();
20+
21+
// Draw a 50x50 region on the first page starting at x50, y50
22+
cy.getByTestId('ba-RegionCreator')
23+
.first()
24+
.trigger('mousedown', {
25+
buttons: 1,
26+
clientX: 50,
27+
clientY: 50,
28+
})
29+
.trigger('mousemove', {
30+
buttons: 1,
31+
clientX: 100,
32+
clientY: 100,
33+
})
34+
.trigger('mouseup');
35+
36+
// Type a message in the reply form and save the new annotation
37+
cy.getByTestId('ba-ReplyField-editor').type('This is an automated test annotation.');
38+
cy.getByTestId('ba-Popup-submit').click();
39+
40+
// Assert that at least one annotation is present on the image
41+
cy.get('[data-testid^="ba-AnnotationTarget"]');
42+
});
43+
});
Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
// <reference types="Cypress" />
2-
describe('Annotations Sanity', () => {
3-
let token;
4-
2+
describe('Annotations', () => {
53
beforeEach(() => {
6-
token = Cypress.env('ACCESS_TOKEN');
74
cy.visit('/');
85
});
96

10-
it('Should load a document with an annotation', () => {
11-
const fileId = Cypress.env('FILE_ID_DOC');
12-
7+
it('should load annotations for a document file', () => {
138
// Show the preview
14-
cy.showPreview(token, fileId);
15-
// Wait for .bp to load viewer
16-
cy.getByTestId('bp').should('have.class', 'bp-loaded');
17-
// Asserts that an annotation point icon has rendered
18-
cy.getByTestId('annotation-marker');
9+
cy.showPreview(Cypress.env('FILE_ID_DOC_SANITY'));
10+
11+
// Wait for viewer to load
12+
cy.get('.bp').should('have.class', 'bp-loaded');
13+
// Wait for annotations to load
14+
cy.get('.bp-doc').should('have.class', 'ba-annotations-loaded');
15+
1916
// Assert document content is present
2017
cy.contains('The Content Platform for Your Apps');
18+
19+
// Assert that at least one annotation is present on the document
20+
cy.get('[data-testid^="ba-AnnotationTarget"]');
21+
});
22+
23+
it('should load annotations for an image file', () => {
24+
// Show the preview
25+
cy.showPreview(Cypress.env('FILE_ID_IMAGE_SANITY'));
26+
27+
// Wait for viewer to load
28+
cy.get('.bp').should('have.class', 'bp-loaded');
29+
// Wait for annotations to load
30+
cy.get('.bp-image').should('have.class', 'ba-annotations-loaded');
31+
32+
// Assert that at least one annotation is present on the image
33+
cy.get('[data-testid^="ba-AnnotationTarget"]');
2134
});
2235
});

test/styles.css

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
.setters-container {
2-
height: 25vh;
32
display: flex;
43
font-size: 75%;
54
justify-content: space-around;
@@ -13,15 +12,17 @@
1312
box-sizing: border-box;
1413
}
1514

16-
.setters-container button,input {
15+
.setters-container button,
16+
.setters-container input {
1717
padding: 5px;
1818
}
1919

20-
.container {
20+
.setters-container .container {
21+
flex: 1 1 50%;
2122
text-align: center;
2223
}
2324

24-
.container > input {
25+
.setters-container .container > input {
2526
text-align: center;
2627
}
2728

test/support/commands.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
// General commands
12
Cypress.Commands.add('getByTestId', testId => cy.get(`[data-testid="${testId}"]`));
23
Cypress.Commands.add('getByTitle', title => cy.get(`[title="${title}"]`));
3-
Cypress.Commands.add('showPreview', (token, fileId) => {
4-
cy.get('[data-testid="token"]').type(token);
4+
5+
// Preview-specific commands
6+
Cypress.Commands.add('showPreview', (fileId, { token } = {}) => {
7+
cy.get('[data-testid="token"]').type(token || Cypress.env('ACCESS_TOKEN'));
58
cy.get('[data-testid="token-set"]').click();
69
cy.get('[data-testid="fileid"]').type(fileId);
710
cy.get('[data-testid="fileid-set"]').click();

test/support/constants.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
Cypress.env({
2-
// NOTE: The token used is a readonly token accessing public data in a demo enterprise.
3-
ACCESS_TOKEN: 'S8wjvjOL9GEK5VtXsQNVMOwSrx1g55oC',
4-
FILE_ID_DOC: '415542803939',
2+
FILE_ID_DOC_SANITY: '694517832310', // Read-only
3+
FILE_ID_IMAGE_SANITY: '694517831110', // Read-only
54
});

0 commit comments

Comments
 (0)