@toptal/davinci-qa 13.1.3-alpha-fix-wrong-data-structure-in-analytics-e998b099.7 → 13.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +10 -7
- package/src/commands/integration-run.test.js +119 -0
- package/src/commands/unit-tests.test.js +217 -0
- package/src/configs/cypress/plugins/parallelization.test.js +112 -0
- package/src/reporters/anvil-results-helper.test.js +131 -0
- package/src/reporters/cypress-anvil-reporter.test.js +263 -0
- package/src/reporters/jest-anvil-reporter.test.js +213 -0
- package/src/utils/jest-args-to-cli-converters.test.js +59 -0
- package/src/utils/styled-components-version-check.test.js +81 -0
- package/src/utils/to-jest-cli-arguments.test.js +32 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toptal/davinci-qa",
|
|
3
|
-
"version": "13.1.3
|
|
3
|
+
"version": "13.1.3",
|
|
4
4
|
"description": "QA package to test your application",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -16,13 +16,17 @@
|
|
|
16
16
|
"davinci-qa": "./bin/davinci-qa.js"
|
|
17
17
|
},
|
|
18
18
|
"main": "./src/index.js",
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"bin",
|
|
22
|
+
"docs",
|
|
23
|
+
"CHANGELOG.md"
|
|
24
|
+
],
|
|
19
25
|
"repository": {
|
|
20
26
|
"type": "git",
|
|
21
27
|
"url": "git+https://github.com/toptal/davinci.git"
|
|
22
28
|
},
|
|
23
29
|
"scripts": {
|
|
24
|
-
"build:package": "../../bin/build-package.js",
|
|
25
|
-
"prepublishOnly": "../../bin/prepublish.js",
|
|
26
30
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
27
31
|
},
|
|
28
32
|
"bugs": {
|
|
@@ -37,7 +41,7 @@
|
|
|
37
41
|
"@cypress/webpack-preprocessor": "^5.12.0",
|
|
38
42
|
"@testing-library/jest-dom": "^5.16.4",
|
|
39
43
|
"@testing-library/react": "^13.3.0",
|
|
40
|
-
"@toptal/davinci-cli-shared": "1.10.2
|
|
44
|
+
"@toptal/davinci-cli-shared": "1.10.2",
|
|
41
45
|
"@types/jest": "^27.5.1",
|
|
42
46
|
"babel-jest": "^28.1.3",
|
|
43
47
|
"cypress": "^10.6.0",
|
|
@@ -58,11 +62,10 @@
|
|
|
58
62
|
"semver": "^7.3.2"
|
|
59
63
|
},
|
|
60
64
|
"devDependencies": {
|
|
61
|
-
"json5": "^2.2.
|
|
65
|
+
"json5": "^2.2.3",
|
|
62
66
|
"mocha": "^10.0.0"
|
|
63
67
|
},
|
|
64
68
|
"peerDependencies": {
|
|
65
69
|
"@toptal/davinci-engine": "3 - 9"
|
|
66
|
-
}
|
|
67
|
-
"gitHead": "e998b09949b7b22fd1305544729bb6665fcfe092"
|
|
70
|
+
}
|
|
68
71
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* eslint-disable import/order -- changing the order messes up with jest mocking */
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
|
|
4
|
+
const originalExistsSync = fs.existsSync
|
|
5
|
+
|
|
6
|
+
const getPackageFilePathMock = jest.fn()
|
|
7
|
+
const getProjectRootFilePathMock = jest.fn(path => `mock:${path}`)
|
|
8
|
+
const fsExistsSyncSpy = jest.spyOn(fs, 'existsSync')
|
|
9
|
+
|
|
10
|
+
jest.mock('@toptal/davinci-cli-shared', () => ({
|
|
11
|
+
...jest.requireActual('@toptal/davinci-cli-shared'),
|
|
12
|
+
runSync: jest.fn(),
|
|
13
|
+
print: {
|
|
14
|
+
red: jest.fn(),
|
|
15
|
+
green: jest.fn(),
|
|
16
|
+
},
|
|
17
|
+
files: {
|
|
18
|
+
getPackageFilePath: getPackageFilePathMock,
|
|
19
|
+
getProjectRootFilePath: getProjectRootFilePathMock,
|
|
20
|
+
},
|
|
21
|
+
packageUtils: {
|
|
22
|
+
checkPrerequirement: jest.fn(),
|
|
23
|
+
getPackagePackageJson: jest.fn(() => ({ peerDependencies: {} })),
|
|
24
|
+
},
|
|
25
|
+
}))
|
|
26
|
+
|
|
27
|
+
const { runSync } = require('@toptal/davinci-cli-shared')
|
|
28
|
+
|
|
29
|
+
const { action } = require('./integration-run')
|
|
30
|
+
|
|
31
|
+
describe('integrationRunCommand', () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
jest.clearAllMocks()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('runs cypress with default options', () => {
|
|
37
|
+
const localConfig = 'mock:cypress.config.js'
|
|
38
|
+
const davinciConfig = 'packages/qa/src/configs/cypress.config.js'
|
|
39
|
+
|
|
40
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciConfig)
|
|
41
|
+
|
|
42
|
+
// fs.existsSync is used in a lot of places, even internally by jest
|
|
43
|
+
// we want to only mock when asking for our files
|
|
44
|
+
fsExistsSyncSpy.mockImplementation((path, ...rest) =>
|
|
45
|
+
path === localConfig ? false : originalExistsSync(path, ...rest)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
action({ options: {} })
|
|
49
|
+
|
|
50
|
+
expect(runSync).toHaveBeenCalledWith('yarn', [
|
|
51
|
+
'cypress',
|
|
52
|
+
'run',
|
|
53
|
+
'--config-file',
|
|
54
|
+
davinciConfig,
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
expect(getPackageFilePathMock).toHaveBeenCalledWith(
|
|
58
|
+
'@toptal/davinci-qa',
|
|
59
|
+
'src/configs/cypress.config.js'
|
|
60
|
+
)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('run cypress with local config, if present', () => {
|
|
64
|
+
const localConfig = 'mock:cypress.config.js'
|
|
65
|
+
const davinciConfig = 'packages/qa/src/configs/cypress.config.js'
|
|
66
|
+
|
|
67
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciConfig)
|
|
68
|
+
|
|
69
|
+
// fs.existsSync is used in a lot of places, even internally by jest
|
|
70
|
+
// we want to only mock when asking for our files
|
|
71
|
+
fsExistsSyncSpy.mockImplementation((path, ...rest) =>
|
|
72
|
+
path === localConfig ? true : originalExistsSync(path, ...rest)
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
action({ options: {} })
|
|
76
|
+
|
|
77
|
+
expect(runSync).toHaveBeenCalledWith('yarn', [
|
|
78
|
+
'cypress',
|
|
79
|
+
'run',
|
|
80
|
+
'--config-file',
|
|
81
|
+
localConfig,
|
|
82
|
+
])
|
|
83
|
+
|
|
84
|
+
expect(getPackageFilePathMock).not.toHaveBeenCalledWith(
|
|
85
|
+
'@toptal/davinci-qa',
|
|
86
|
+
'src/configs/cypress.config.js'
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('runs cypress with custom options', () => {
|
|
91
|
+
const localConfig = 'mock:cypress.config.js'
|
|
92
|
+
const davinciConfig = 'packages/qa/src/configs/cypress.config.js'
|
|
93
|
+
const spec = 'cypress/integration/activation_flow.spec.ts'
|
|
94
|
+
|
|
95
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciConfig)
|
|
96
|
+
|
|
97
|
+
// fs.existsSync is used in a lot of places, even internally by jest
|
|
98
|
+
// we want to only mock when asking for our files
|
|
99
|
+
fsExistsSyncSpy.mockImplementation((path, ...rest) =>
|
|
100
|
+
path === localConfig ? false : originalExistsSync(path, ...rest)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
action({ options: { spec } })
|
|
104
|
+
|
|
105
|
+
expect(runSync).toHaveBeenCalledWith('yarn', [
|
|
106
|
+
'cypress',
|
|
107
|
+
'run',
|
|
108
|
+
'--config-file',
|
|
109
|
+
davinciConfig,
|
|
110
|
+
'--spec',
|
|
111
|
+
spec,
|
|
112
|
+
])
|
|
113
|
+
|
|
114
|
+
expect(getPackageFilePathMock).toHaveBeenCalledWith(
|
|
115
|
+
'@toptal/davinci-qa',
|
|
116
|
+
'src/configs/cypress.config.js'
|
|
117
|
+
)
|
|
118
|
+
})
|
|
119
|
+
})
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
const jestRunCLIMock = jest
|
|
2
|
+
.fn()
|
|
3
|
+
.mockResolvedValue({ results: { success: true } })
|
|
4
|
+
const getPackageFilePathMock = jest.fn()
|
|
5
|
+
const getProjectRootFilePathMock = jest.fn()
|
|
6
|
+
const getProjectRootFileContentMock = jest.fn().mockReturnValue({
|
|
7
|
+
devDependencies: {},
|
|
8
|
+
dependencies: {},
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
jest.mock('@toptal/davinci-cli-shared', () => ({
|
|
12
|
+
runSync: jest.fn(),
|
|
13
|
+
print: {
|
|
14
|
+
green: jest.fn(),
|
|
15
|
+
grey: jest.fn(),
|
|
16
|
+
red: jest.fn(),
|
|
17
|
+
},
|
|
18
|
+
files: {
|
|
19
|
+
getPackageFilePath: getPackageFilePathMock,
|
|
20
|
+
getProjectRootFileContent: getProjectRootFileContentMock,
|
|
21
|
+
getProjectRootFilePath: getProjectRootFilePathMock,
|
|
22
|
+
},
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
jest.mock('jest', () => ({
|
|
26
|
+
runCLI: jestRunCLIMock,
|
|
27
|
+
}))
|
|
28
|
+
|
|
29
|
+
const { action } = require('./unit-tests')
|
|
30
|
+
const originalEnv = process.env
|
|
31
|
+
|
|
32
|
+
describe('unitTestsCommand', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jest.clearAllMocks()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
process.env = originalEnv
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('when running locally', () => {
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
delete process.env.CI
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('calls the jest CLI without additional reporters', async () => {
|
|
47
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
48
|
+
|
|
49
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
50
|
+
|
|
51
|
+
await action({})
|
|
52
|
+
|
|
53
|
+
expect(jestRunCLIMock).toHaveBeenCalledWith(
|
|
54
|
+
{ config: davinciJestConfigPath, testPathPattern: [] },
|
|
55
|
+
expect.anything()
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('when running on CI', () => {
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
process.env.CI = true
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('calls the jest CLI with default Davinci reporters', async () => {
|
|
66
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
67
|
+
|
|
68
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
69
|
+
|
|
70
|
+
await action({})
|
|
71
|
+
|
|
72
|
+
expect(jestRunCLIMock).toHaveBeenCalledWith(
|
|
73
|
+
expect.objectContaining({
|
|
74
|
+
reporters: [
|
|
75
|
+
[
|
|
76
|
+
'jest-silent-reporter',
|
|
77
|
+
{
|
|
78
|
+
useDots: true,
|
|
79
|
+
showPaths: true,
|
|
80
|
+
showWarnings: true,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
'jest-junit',
|
|
85
|
+
{
|
|
86
|
+
outputDirectory: 'reports',
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
'jest-html-reporters',
|
|
91
|
+
{
|
|
92
|
+
publicPath: './reports',
|
|
93
|
+
inlineSource: true,
|
|
94
|
+
failureMessageOnly: 2,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
],
|
|
98
|
+
}),
|
|
99
|
+
expect.anything()
|
|
100
|
+
)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('returns the anvil reporter when anvilTag is set', async () => {
|
|
104
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
105
|
+
|
|
106
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
107
|
+
|
|
108
|
+
await action({ options: { anvilTag: 'platform' } })
|
|
109
|
+
|
|
110
|
+
expect(jestRunCLIMock).toHaveBeenCalledWith(
|
|
111
|
+
expect.objectContaining({
|
|
112
|
+
reporters: [
|
|
113
|
+
[
|
|
114
|
+
'jest-silent-reporter',
|
|
115
|
+
{
|
|
116
|
+
useDots: true,
|
|
117
|
+
showPaths: true,
|
|
118
|
+
showWarnings: true,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
[
|
|
122
|
+
'jest-junit',
|
|
123
|
+
{
|
|
124
|
+
outputDirectory: 'reports',
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
[
|
|
128
|
+
'jest-html-reporters',
|
|
129
|
+
{
|
|
130
|
+
publicPath: './reports',
|
|
131
|
+
inlineSource: true,
|
|
132
|
+
failureMessageOnly: 2,
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
[
|
|
136
|
+
expect.stringContaining(
|
|
137
|
+
'davinci/packages/qa/src/reporters/jest-anvil-reporter.js'
|
|
138
|
+
),
|
|
139
|
+
{
|
|
140
|
+
anvilTag: 'platform',
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
],
|
|
144
|
+
}),
|
|
145
|
+
expect.anything()
|
|
146
|
+
)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('allows overriding of the default Davinci reporters via custom configuration', async () => {
|
|
150
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
151
|
+
|
|
152
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
153
|
+
const customCLIReporter = 'My-CLI-Reporter'
|
|
154
|
+
|
|
155
|
+
await action({
|
|
156
|
+
options: {
|
|
157
|
+
anvilTag: 'MyTag',
|
|
158
|
+
reporters: customCLIReporter,
|
|
159
|
+
},
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
expect(jestRunCLIMock).toHaveBeenCalledWith(
|
|
163
|
+
expect.objectContaining({
|
|
164
|
+
reporters: [customCLIReporter],
|
|
165
|
+
}),
|
|
166
|
+
expect.anything()
|
|
167
|
+
)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('allows overriding the default Davinci reporters via custom jest config', async () => {
|
|
171
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
172
|
+
|
|
173
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
174
|
+
const customJestConfigReporter = 'My-Jest-Config-Reporter'
|
|
175
|
+
|
|
176
|
+
getProjectRootFileContentMock.mockReturnValue({
|
|
177
|
+
reporters: customJestConfigReporter,
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
await action({ options: { config: {} } })
|
|
181
|
+
|
|
182
|
+
expect(jestRunCLIMock).toHaveBeenCalledWith(
|
|
183
|
+
expect.objectContaining({
|
|
184
|
+
reporters: [customJestConfigReporter],
|
|
185
|
+
}),
|
|
186
|
+
expect.anything()
|
|
187
|
+
)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('prioritizes the CLI reporters over the custom jest config or the default Davinci reporters', async () => {
|
|
191
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
192
|
+
|
|
193
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
194
|
+
const customCLIReporter = 'My-CLI-Reporter'
|
|
195
|
+
const customJestConfigReporter = 'My-Jest-Config-Reporter'
|
|
196
|
+
|
|
197
|
+
getProjectRootFileContentMock.mockReturnValue({
|
|
198
|
+
reporters: customJestConfigReporter,
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
await action({
|
|
202
|
+
options: {
|
|
203
|
+
anvilTag: 'MyTag',
|
|
204
|
+
reporters: customCLIReporter,
|
|
205
|
+
config: {},
|
|
206
|
+
},
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
expect(jestRunCLIMock).toHaveBeenCalledWith(
|
|
210
|
+
expect.objectContaining({
|
|
211
|
+
reporters: [customCLIReporter],
|
|
212
|
+
}),
|
|
213
|
+
expect.anything()
|
|
214
|
+
)
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const glob = require('glob')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
|
|
4
|
+
const parallelization = require('./parallelization')
|
|
5
|
+
|
|
6
|
+
const mockedConfig = {
|
|
7
|
+
specPattern: '**.test.js',
|
|
8
|
+
}
|
|
9
|
+
const mockedTestFiles = [
|
|
10
|
+
'test1.test.js',
|
|
11
|
+
'test2.test.js',
|
|
12
|
+
'test3.test.js',
|
|
13
|
+
'test4.test.js',
|
|
14
|
+
]
|
|
15
|
+
const mockedSizes = {
|
|
16
|
+
'test1.test.js': 128,
|
|
17
|
+
'test2.test.js': 256,
|
|
18
|
+
'test3.test.js': 512,
|
|
19
|
+
'test4.test.js': 1024,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
jest.mock('test-project/test1.test.js', () => {}, {
|
|
23
|
+
virtual: true,
|
|
24
|
+
})
|
|
25
|
+
jest.mock('test-project/test2.test.js', () => {}, {
|
|
26
|
+
virtual: true,
|
|
27
|
+
})
|
|
28
|
+
jest.mock('test-project/test3.test.js', () => {}, {
|
|
29
|
+
virtual: true,
|
|
30
|
+
})
|
|
31
|
+
jest.mock('test-project/test4.test.js', () => {}, {
|
|
32
|
+
virtual: true,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('Cypress CI parallelization', () => {
|
|
36
|
+
const env = process.env
|
|
37
|
+
let config = mockedConfig
|
|
38
|
+
let globSyncMock
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
process.env = { ...env }
|
|
42
|
+
config = { ...mockedConfig }
|
|
43
|
+
|
|
44
|
+
globSyncMock = jest.spyOn(glob, 'sync')
|
|
45
|
+
jest.spyOn(fs, 'statSync').mockImplementation(fileName => ({
|
|
46
|
+
size: mockedSizes[fileName],
|
|
47
|
+
}))
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
jest.restoreAllMocks()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('Sort files by size and split in two parallel groups', () => {
|
|
55
|
+
it('returns first half', () => {
|
|
56
|
+
process.env.GROUP_INDEX = 0
|
|
57
|
+
process.env.PARALLEL_GROUPS = 2
|
|
58
|
+
|
|
59
|
+
globSyncMock.mockImplementation(() => mockedTestFiles.slice(0))
|
|
60
|
+
|
|
61
|
+
parallelization(config)
|
|
62
|
+
|
|
63
|
+
expect(config.specPattern).toEqual(['test4.test.js', 'test2.test.js'])
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('returns second half', () => {
|
|
67
|
+
process.env.GROUP_INDEX = 1
|
|
68
|
+
process.env.PARALLEL_GROUPS = 2
|
|
69
|
+
|
|
70
|
+
globSyncMock.mockImplementation(() => mockedTestFiles.slice(0))
|
|
71
|
+
|
|
72
|
+
parallelization(config)
|
|
73
|
+
|
|
74
|
+
expect(config.specPattern).toEqual(['test3.test.js', 'test1.test.js'])
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('When there is only 1 parallel group', () => {
|
|
79
|
+
it('returns spec pattern', () => {
|
|
80
|
+
process.env.GROUP_INDEX = 0
|
|
81
|
+
process.env.PARALLEL_GROUPS = 1
|
|
82
|
+
|
|
83
|
+
parallelization(config)
|
|
84
|
+
|
|
85
|
+
expect(config.specPattern).toBe('**.test.js')
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
describe('When group index is lower than 0', () => {
|
|
90
|
+
it('returns spec pattern', () => {
|
|
91
|
+
process.env.GROUP_INDEX = -1
|
|
92
|
+
process.env.PARALLEL_GROUPS = 3
|
|
93
|
+
|
|
94
|
+
parallelization(config)
|
|
95
|
+
|
|
96
|
+
expect(config.specPattern).toBe('**.test.js')
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
describe('When there are less test files than testing groups', () => {
|
|
101
|
+
it('returns empty array for a group', () => {
|
|
102
|
+
process.env.GROUP_INDEX = 1
|
|
103
|
+
process.env.PARALLEL_GROUPS = 2
|
|
104
|
+
|
|
105
|
+
globSyncMock.mockImplementation(() => mockedTestFiles.slice(0, 1))
|
|
106
|
+
|
|
107
|
+
parallelization(config)
|
|
108
|
+
|
|
109
|
+
expect(config.specPattern).toEqual([])
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
})
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const fs = require('fs-extra')
|
|
2
|
+
const { print } = require('@toptal/davinci-cli-shared')
|
|
3
|
+
|
|
4
|
+
const { anvilMapper, generateAnvilResults } = require('./anvil-results-helper')
|
|
5
|
+
|
|
6
|
+
describe('Anvil results helper', () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
jest.resetModules()
|
|
9
|
+
jest.resetAllMocks()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe('anvilMapper', () => {
|
|
13
|
+
it('outputs an Anvil-compatible object', () => {
|
|
14
|
+
const mappedValue = anvilMapper({
|
|
15
|
+
fileName:
|
|
16
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
17
|
+
backtrace: null,
|
|
18
|
+
description: '1 + 1 returns 2',
|
|
19
|
+
durationInSeconds: 0.003,
|
|
20
|
+
error: null,
|
|
21
|
+
lineNumber: 2,
|
|
22
|
+
pendingMessage: null,
|
|
23
|
+
scenarioName: 'Example test suite/1 + 1 returns 2',
|
|
24
|
+
status: 'passed',
|
|
25
|
+
tag: 'platform',
|
|
26
|
+
testType: 'unit',
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
expect(mappedValue).toEqual({
|
|
30
|
+
file_name:
|
|
31
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
32
|
+
line_number: 2,
|
|
33
|
+
status: 'passed',
|
|
34
|
+
duration: 0.003,
|
|
35
|
+
scenario_name: 'Example test suite/1 + 1 returns 2',
|
|
36
|
+
description: '1 + 1 returns 2',
|
|
37
|
+
error: null,
|
|
38
|
+
backtrace: null,
|
|
39
|
+
test_type: 'unit',
|
|
40
|
+
pending_message: null,
|
|
41
|
+
tag: 'platform',
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('converts "todo" status to pending', () => {
|
|
46
|
+
const mappedValue = anvilMapper({ status: 'todo' })
|
|
47
|
+
|
|
48
|
+
expect(mappedValue.status).toBe('pending')
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('generateAnvilResults', () => {
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
// To avoid creating files
|
|
55
|
+
jest.spyOn(fs, 'writeJsonSync').mockImplementation(() => {})
|
|
56
|
+
jest.spyOn(fs, 'outputJsonSync').mockImplementation(() => {})
|
|
57
|
+
jest
|
|
58
|
+
.spyOn(fs, 'readJsonSync')
|
|
59
|
+
.mockImplementation(() => ({ test_results: [] }))
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('creates a report with the data passed in', () => {
|
|
63
|
+
const writeJsonMock = jest.spyOn(fs, 'writeJsonSync')
|
|
64
|
+
const printMock = jest.spyOn(print, 'green')
|
|
65
|
+
|
|
66
|
+
generateAnvilResults('anvil_cypress_test_results.json', [{ test: 123 }])
|
|
67
|
+
|
|
68
|
+
expect(writeJsonMock).toHaveBeenCalledWith(
|
|
69
|
+
'./reports/anvil_cypress_test_results.json',
|
|
70
|
+
{ test_results: [{ test: 123 }] }
|
|
71
|
+
)
|
|
72
|
+
expect(printMock).toHaveBeenCalledWith(
|
|
73
|
+
'[anvil-reporter] Anvil reports generated successfully!'
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('throws an error when unable to create report', () => {
|
|
78
|
+
const mockError = new Error('My error!')
|
|
79
|
+
|
|
80
|
+
jest.spyOn(fs, 'existsSync').mockImplementation(() => {
|
|
81
|
+
throw mockError
|
|
82
|
+
})
|
|
83
|
+
const printMock = jest.spyOn(print, 'red')
|
|
84
|
+
|
|
85
|
+
expect(() =>
|
|
86
|
+
generateAnvilResults('anvil_cypress_test_results.json', [{ test: 123 }])
|
|
87
|
+
).toThrow()
|
|
88
|
+
|
|
89
|
+
expect(printMock).toHaveBeenCalledTimes(1)
|
|
90
|
+
expect(printMock).toHaveBeenCalledWith(
|
|
91
|
+
'[anvil-reporter] Failed to create Anvil test results!',
|
|
92
|
+
mockError
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('merges test results when previous reports exist', () => {
|
|
97
|
+
const writeJsonMock = jest.spyOn(fs, 'writeJsonSync')
|
|
98
|
+
|
|
99
|
+
jest.spyOn(fs, 'existsSync').mockImplementation(() => true)
|
|
100
|
+
jest
|
|
101
|
+
.spyOn(fs, 'readJsonSync')
|
|
102
|
+
.mockImplementation(() => ({ test_results: [{ name: 'my_results' }] }))
|
|
103
|
+
|
|
104
|
+
generateAnvilResults('anvil_cypress_test_results.json', [
|
|
105
|
+
{ name: 'my_new_results' },
|
|
106
|
+
])
|
|
107
|
+
|
|
108
|
+
expect(writeJsonMock).toHaveBeenCalledWith(
|
|
109
|
+
'./reports/anvil_cypress_test_results.json',
|
|
110
|
+
{
|
|
111
|
+
test_results: [{ name: 'my_results' }, { name: 'my_new_results' }],
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('creates a new file with empty results when one does not exist', () => {
|
|
117
|
+
const outputJsonMock = jest.spyOn(fs, 'outputJsonSync')
|
|
118
|
+
|
|
119
|
+
jest.spyOn(fs, 'existsSync').mockImplementation(() => false)
|
|
120
|
+
|
|
121
|
+
generateAnvilResults('anvil_cypress_test_results.json', [
|
|
122
|
+
{ name: 'my_new_results' },
|
|
123
|
+
])
|
|
124
|
+
|
|
125
|
+
expect(outputJsonMock).toHaveBeenCalledWith(
|
|
126
|
+
'./reports/anvil_cypress_test_results.json',
|
|
127
|
+
{ test_results: [] }
|
|
128
|
+
)
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/* eslint-disable jest/no-done-callback */
|
|
2
|
+
// If you need to extend these tests, have a look at these other reporters for inspiration:
|
|
3
|
+
// - https://github.com/adamgruber/mochawesome/blob/963f073fe3f4522070788a702329dd6b61014df3/test/reporter.test.js
|
|
4
|
+
// - https://github.com/michaelleeallen/mocha-junit-reporter/blob/3b65764449f6f3a0ec6f54da5842a2a21d788382/test/mocha-junit-reporter-spec.js#L176
|
|
5
|
+
const generateAnvilResultsMock = jest.fn()
|
|
6
|
+
|
|
7
|
+
jest.mock('./anvil-results-helper', () => ({
|
|
8
|
+
...jest.requireActual('./anvil-results-helper'),
|
|
9
|
+
generateAnvilResults: generateAnvilResultsMock,
|
|
10
|
+
}))
|
|
11
|
+
const { print } = require('@toptal/davinci-cli-shared')
|
|
12
|
+
const Mocha = require('mocha')
|
|
13
|
+
const { AssertionError } = require('assert')
|
|
14
|
+
|
|
15
|
+
const CypressAnvilReporter = require('./cypress-anvil-reporter')
|
|
16
|
+
|
|
17
|
+
const { Runner, Suite, Test } = Mocha
|
|
18
|
+
|
|
19
|
+
const createRunner = suite => {
|
|
20
|
+
const runner = new Runner(suite)
|
|
21
|
+
|
|
22
|
+
runner.stats = {
|
|
23
|
+
passes: 0,
|
|
24
|
+
duration: 0,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return runner
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const configureReporter = (runner, reporter, options = {}) => {
|
|
31
|
+
const mocha = new Mocha({
|
|
32
|
+
reporter: reporter,
|
|
33
|
+
allowUncaught: true,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
new mocha._reporter(runner, {
|
|
37
|
+
reporterOptions: options,
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe('Cypress Anvil reporter', () => {
|
|
42
|
+
const rootSuiteName = 'my root suite'
|
|
43
|
+
const testName = 'my test'
|
|
44
|
+
const anvilTag = 'talent_portal'
|
|
45
|
+
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
jest.resetModules()
|
|
48
|
+
jest.resetAllMocks()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('generates an Anvil-compatible report when anvilTag is set', done => {
|
|
52
|
+
const suite = new Suite(rootSuiteName, 'root').addTest(
|
|
53
|
+
new Test(testName, () => {})
|
|
54
|
+
)
|
|
55
|
+
const runner = createRunner(suite)
|
|
56
|
+
|
|
57
|
+
configureReporter(runner, CypressAnvilReporter, { anvilTag })
|
|
58
|
+
|
|
59
|
+
runner.run(failures => {
|
|
60
|
+
expect(failures).toBe(0)
|
|
61
|
+
expect(generateAnvilResultsMock).toHaveBeenCalledWith(
|
|
62
|
+
'anvil_cypress_test_results.json',
|
|
63
|
+
[
|
|
64
|
+
{
|
|
65
|
+
status: 'passed',
|
|
66
|
+
duration: expect.any(Number),
|
|
67
|
+
scenario_name: `${rootSuiteName}/${testName}`,
|
|
68
|
+
description: testName,
|
|
69
|
+
error: null,
|
|
70
|
+
backtrace: null,
|
|
71
|
+
test_type: 'integration',
|
|
72
|
+
pending_message: null,
|
|
73
|
+
tag: anvilTag,
|
|
74
|
+
},
|
|
75
|
+
]
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
done()
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('does not generate a report if anvilTag is not specified', done => {
|
|
83
|
+
const printSpy = jest.spyOn(print, 'yellow')
|
|
84
|
+
const suite = new Suite(rootSuiteName, 'root').addTest(
|
|
85
|
+
new Test(testName, () => {})
|
|
86
|
+
)
|
|
87
|
+
const runner = createRunner(suite)
|
|
88
|
+
|
|
89
|
+
configureReporter(runner, CypressAnvilReporter)
|
|
90
|
+
|
|
91
|
+
runner.run(() => {
|
|
92
|
+
expect(printSpy).toHaveBeenCalledWith(
|
|
93
|
+
expect.stringContaining(
|
|
94
|
+
"[anvil-reporter] --anvilTag option is missing! anvil_cypress_test_results.json won't be generated."
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
expect(generateAnvilResultsMock).not.toHaveBeenCalled()
|
|
98
|
+
|
|
99
|
+
done()
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('returns the scenario name with all parents listed', done => {
|
|
104
|
+
const grandchildSuiteName = 'my grandchild suite'
|
|
105
|
+
const childSuiteName = 'my child suite'
|
|
106
|
+
|
|
107
|
+
const grandchildSuite = new Suite(grandchildSuiteName, 'root').addTest(
|
|
108
|
+
new Test(testName, () => {})
|
|
109
|
+
)
|
|
110
|
+
const childSuite = new Suite(childSuiteName, 'root').addSuite(
|
|
111
|
+
grandchildSuite
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
new Suite(rootSuiteName, 'root').addSuite(childSuite)
|
|
115
|
+
|
|
116
|
+
const runner = createRunner(grandchildSuite)
|
|
117
|
+
|
|
118
|
+
configureReporter(runner, CypressAnvilReporter, { anvilTag })
|
|
119
|
+
|
|
120
|
+
runner.run(failures => {
|
|
121
|
+
expect(failures).toBe(0)
|
|
122
|
+
expect(generateAnvilResultsMock).toHaveBeenCalledWith(
|
|
123
|
+
'anvil_cypress_test_results.json',
|
|
124
|
+
[
|
|
125
|
+
{
|
|
126
|
+
status: 'passed',
|
|
127
|
+
duration: expect.any(Number),
|
|
128
|
+
scenario_name: `${rootSuiteName}/${childSuiteName}/${grandchildSuiteName}/${testName}`,
|
|
129
|
+
description: testName,
|
|
130
|
+
error: null,
|
|
131
|
+
backtrace: null,
|
|
132
|
+
test_type: 'integration',
|
|
133
|
+
pending_message: null,
|
|
134
|
+
tag: anvilTag,
|
|
135
|
+
},
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
done()
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('returns errors and backtrace when tests fail', done => {
|
|
144
|
+
const errorMessage = 'Expected foo, got bar'
|
|
145
|
+
const suite = new Suite(rootSuiteName, 'root').addTest(
|
|
146
|
+
new Test(testName, callback => {
|
|
147
|
+
callback(new AssertionError({ message: errorMessage }))
|
|
148
|
+
})
|
|
149
|
+
)
|
|
150
|
+
const runner = createRunner(suite)
|
|
151
|
+
|
|
152
|
+
configureReporter(runner, CypressAnvilReporter, { anvilTag })
|
|
153
|
+
|
|
154
|
+
runner.run(failures => {
|
|
155
|
+
expect(failures).toBe(1)
|
|
156
|
+
expect(generateAnvilResultsMock).toHaveBeenCalledWith(
|
|
157
|
+
'anvil_cypress_test_results.json',
|
|
158
|
+
[
|
|
159
|
+
{
|
|
160
|
+
status: 'failed',
|
|
161
|
+
duration: expect.any(Number),
|
|
162
|
+
scenario_name: `${rootSuiteName}/${testName}`,
|
|
163
|
+
description: testName,
|
|
164
|
+
error: errorMessage,
|
|
165
|
+
backtrace: expect.arrayContaining([
|
|
166
|
+
expect.stringMatching(
|
|
167
|
+
new RegExp(
|
|
168
|
+
`AssertionError.*${errorMessage}.*at new AssertionError`,
|
|
169
|
+
'gms'
|
|
170
|
+
)
|
|
171
|
+
),
|
|
172
|
+
]),
|
|
173
|
+
test_type: 'integration',
|
|
174
|
+
pending_message: null,
|
|
175
|
+
tag: anvilTag,
|
|
176
|
+
},
|
|
177
|
+
]
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
done()
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('supports retried tests', done => {
|
|
185
|
+
const suite = new Suite(rootSuiteName, 'root').retries(2).addTest(
|
|
186
|
+
new Test(testName, callback => {
|
|
187
|
+
expect(1).toBe(2)
|
|
188
|
+
|
|
189
|
+
callback()
|
|
190
|
+
})
|
|
191
|
+
)
|
|
192
|
+
const runner = createRunner(suite)
|
|
193
|
+
|
|
194
|
+
configureReporter(runner, CypressAnvilReporter, { anvilTag })
|
|
195
|
+
|
|
196
|
+
runner.run(failures => {
|
|
197
|
+
expect(failures).toBe(1)
|
|
198
|
+
expect(generateAnvilResultsMock).toHaveBeenCalledWith(
|
|
199
|
+
'anvil_cypress_test_results.json',
|
|
200
|
+
[
|
|
201
|
+
{
|
|
202
|
+
status: 'retried',
|
|
203
|
+
duration: expect.any(Number),
|
|
204
|
+
scenario_name: `${rootSuiteName}/${testName}`,
|
|
205
|
+
description: testName,
|
|
206
|
+
error: null,
|
|
207
|
+
backtrace: null,
|
|
208
|
+
test_type: 'integration',
|
|
209
|
+
pending_message: null,
|
|
210
|
+
tag: anvilTag,
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
status: 'retried',
|
|
214
|
+
duration: expect.any(Number),
|
|
215
|
+
scenario_name: `${rootSuiteName}/${testName}`,
|
|
216
|
+
description: testName,
|
|
217
|
+
error: null,
|
|
218
|
+
backtrace: null,
|
|
219
|
+
test_type: 'integration',
|
|
220
|
+
pending_message: null,
|
|
221
|
+
tag: anvilTag,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
status: 'failed',
|
|
225
|
+
duration: expect.any(Number),
|
|
226
|
+
scenario_name: `${rootSuiteName}/${testName}`,
|
|
227
|
+
description: testName,
|
|
228
|
+
error: expect.anything(),
|
|
229
|
+
backtrace: expect.anything(),
|
|
230
|
+
test_type: 'integration',
|
|
231
|
+
pending_message: null,
|
|
232
|
+
tag: anvilTag,
|
|
233
|
+
},
|
|
234
|
+
]
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
done()
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('calls the anvil test result mapper', done => {
|
|
242
|
+
const anvilMapperSpy = jest.fn()
|
|
243
|
+
|
|
244
|
+
jest.mock('./anvil-results-helper', () => ({
|
|
245
|
+
anvilMapper: anvilMapperSpy,
|
|
246
|
+
generateAnvilResults: jest.fn(),
|
|
247
|
+
}))
|
|
248
|
+
const newCypressAnvilReporter = require('./cypress-anvil-reporter')
|
|
249
|
+
|
|
250
|
+
const suite = new Suite('My suite', 'root').addTest(
|
|
251
|
+
new Test('My test', () => {})
|
|
252
|
+
)
|
|
253
|
+
const runner = createRunner(suite)
|
|
254
|
+
|
|
255
|
+
configureReporter(runner, newCypressAnvilReporter, { anvilTag })
|
|
256
|
+
|
|
257
|
+
runner.run(() => {
|
|
258
|
+
expect(anvilMapperSpy).toHaveBeenCalledTimes(1)
|
|
259
|
+
|
|
260
|
+
done()
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
})
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
const generateAnvilResultsMock = jest.fn()
|
|
2
|
+
|
|
3
|
+
jest.mock('./anvil-results-helper', () => ({
|
|
4
|
+
...jest.requireActual('./anvil-results-helper'),
|
|
5
|
+
generateAnvilResults: generateAnvilResultsMock,
|
|
6
|
+
}))
|
|
7
|
+
|
|
8
|
+
const { print } = require('@toptal/davinci-cli-shared')
|
|
9
|
+
|
|
10
|
+
const JestAnvilReporter = require('./jest-anvil-reporter')
|
|
11
|
+
const {
|
|
12
|
+
passedTestResults,
|
|
13
|
+
failedTestResults,
|
|
14
|
+
skippedTestResults,
|
|
15
|
+
combinedTestResults,
|
|
16
|
+
toDoTestResults,
|
|
17
|
+
} = require('./test-result-mocks')
|
|
18
|
+
|
|
19
|
+
describe('Jest Anvil reporter', () => {
|
|
20
|
+
const expectedPassedTestResults = [
|
|
21
|
+
{
|
|
22
|
+
file_name:
|
|
23
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
24
|
+
line_number: 2,
|
|
25
|
+
status: 'passed',
|
|
26
|
+
duration: 0.003,
|
|
27
|
+
scenario_name: 'Example test suite/1 + 1 returns 2',
|
|
28
|
+
description: '1 + 1 returns 2',
|
|
29
|
+
error: null,
|
|
30
|
+
backtrace: null,
|
|
31
|
+
test_type: 'unit',
|
|
32
|
+
pending_message: null,
|
|
33
|
+
tag: 'platform',
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
const expectedFailedTestResults = [
|
|
38
|
+
{
|
|
39
|
+
file_name:
|
|
40
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
41
|
+
line_number: 2,
|
|
42
|
+
status: 'failed',
|
|
43
|
+
duration: 0.006,
|
|
44
|
+
scenario_name: 'Example test suite/1 + 1 returns 3',
|
|
45
|
+
description: '1 + 1 returns 3',
|
|
46
|
+
error:
|
|
47
|
+
'Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32m3\u001b[39m\nReceived: \u001b[31m2\u001b[39m\n at Object.<anonymous> (/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js:3:17)\n at Object.asyncJestTest (/davinci/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:45:12\n at new Promise (<anonymous>)\n at mapper (/davinci/node_modules/jest-jasmine2/build/queueRunner.js:28:19)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:75:41',
|
|
48
|
+
backtrace: [
|
|
49
|
+
'Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32m3\u001b[39m\nReceived: \u001b[31m2\u001b[39m\n at Object.<anonymous> (/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js:3:17)\n at Object.asyncJestTest (/davinci/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:45:12\n at new Promise (<anonymous>)\n at mapper (/davinci/node_modules/jest-jasmine2/build/queueRunner.js:28:19)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:75:41',
|
|
50
|
+
],
|
|
51
|
+
test_type: 'unit',
|
|
52
|
+
pending_message: null,
|
|
53
|
+
tag: 'platform',
|
|
54
|
+
},
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
const expectedSkippedTestResults = [
|
|
58
|
+
{
|
|
59
|
+
file_name:
|
|
60
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
61
|
+
line_number: 2,
|
|
62
|
+
status: 'pending',
|
|
63
|
+
duration: 0,
|
|
64
|
+
scenario_name: 'Example test suite/1 + 1 returns 2',
|
|
65
|
+
description: '1 + 1 returns 2',
|
|
66
|
+
error: null,
|
|
67
|
+
backtrace: null,
|
|
68
|
+
test_type: 'unit',
|
|
69
|
+
pending_message: null,
|
|
70
|
+
tag: 'platform',
|
|
71
|
+
},
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
const expectedToDoTestResults = [
|
|
75
|
+
{
|
|
76
|
+
file_name:
|
|
77
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
78
|
+
line_number: null,
|
|
79
|
+
status: 'pending',
|
|
80
|
+
duration: 0,
|
|
81
|
+
scenario_name: 'Example test suite/1+1 returns 2',
|
|
82
|
+
description: '1+1 returns 2',
|
|
83
|
+
error: null,
|
|
84
|
+
backtrace: null,
|
|
85
|
+
test_type: 'unit',
|
|
86
|
+
pending_message: null,
|
|
87
|
+
tag: 'platform',
|
|
88
|
+
},
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
const expectedCombinedTestResults = [
|
|
92
|
+
{
|
|
93
|
+
file_name:
|
|
94
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
95
|
+
line_number: 2,
|
|
96
|
+
status: 'passed',
|
|
97
|
+
duration: 0.005,
|
|
98
|
+
scenario_name: 'Example test suite/1 + 1 returns 2 (passed)',
|
|
99
|
+
description: '1 + 1 returns 2 (passed)',
|
|
100
|
+
error: null,
|
|
101
|
+
backtrace: null,
|
|
102
|
+
test_type: 'unit',
|
|
103
|
+
pending_message: null,
|
|
104
|
+
tag: 'platform',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
file_name:
|
|
108
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
109
|
+
line_number: 6,
|
|
110
|
+
status: 'failed',
|
|
111
|
+
duration: 0.007,
|
|
112
|
+
scenario_name: 'Example test suite/1 + 1 returns 3 (failed)',
|
|
113
|
+
description: '1 + 1 returns 3 (failed)',
|
|
114
|
+
error:
|
|
115
|
+
'Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32m3\u001b[39m\nReceived: \u001b[31m2\u001b[39m\n at Object.<anonymous> (/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js:7:17)\n at Object.asyncJestTest (/davinci/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:45:12\n at new Promise (<anonymous>)\n at mapper (/davinci/node_modules/jest-jasmine2/build/queueRunner.js:28:19)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:75:41',
|
|
116
|
+
backtrace: [
|
|
117
|
+
'Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32m3\u001b[39m\nReceived: \u001b[31m2\u001b[39m\n at Object.<anonymous> (/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js:7:17)\n at Object.asyncJestTest (/davinci/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:45:12\n at new Promise (<anonymous>)\n at mapper (/davinci/node_modules/jest-jasmine2/build/queueRunner.js:28:19)\n at /davinci/node_modules/jest-jasmine2/build/queueRunner.js:75:41',
|
|
118
|
+
],
|
|
119
|
+
test_type: 'unit',
|
|
120
|
+
pending_message: null,
|
|
121
|
+
tag: 'platform',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
file_name:
|
|
125
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
126
|
+
line_number: 10,
|
|
127
|
+
status: 'pending',
|
|
128
|
+
duration: 0,
|
|
129
|
+
scenario_name: 'Example test suite/1 + 1 returns 2 (skipped)',
|
|
130
|
+
description: '1 + 1 returns 2 (skipped)',
|
|
131
|
+
error: null,
|
|
132
|
+
backtrace: null,
|
|
133
|
+
test_type: 'unit',
|
|
134
|
+
pending_message: null,
|
|
135
|
+
tag: 'platform',
|
|
136
|
+
},
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
beforeEach(() => {
|
|
140
|
+
jest.resetModules()
|
|
141
|
+
jest.resetAllMocks()
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it.each`
|
|
145
|
+
input | expectedOutput | testType
|
|
146
|
+
${passedTestResults} | ${expectedPassedTestResults} | ${'passing tests'}
|
|
147
|
+
${failedTestResults} | ${expectedFailedTestResults} | ${'failing tests'}
|
|
148
|
+
${skippedTestResults} | ${expectedSkippedTestResults} | ${'skipped tests'}
|
|
149
|
+
${toDoTestResults} | ${expectedToDoTestResults} | ${'todo tests'}
|
|
150
|
+
${combinedTestResults} | ${expectedCombinedTestResults} | ${'a combination of test results'}
|
|
151
|
+
`(
|
|
152
|
+
'calls generateAnvilResults with a payload matching Anvil for $testType',
|
|
153
|
+
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
|
154
|
+
({ input, expectedOutput, testType }) => {
|
|
155
|
+
const jestAnvilReporter = new JestAnvilReporter(undefined, {
|
|
156
|
+
anvilTag: 'platform',
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
jestAnvilReporter.onRunComplete(undefined, input)
|
|
160
|
+
|
|
161
|
+
expect(generateAnvilResultsMock).toHaveBeenCalledWith(
|
|
162
|
+
'anvil_jest_test_results.json',
|
|
163
|
+
expectedOutput
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
it('prints warning and exits when anvilTag is not defined', () => {
|
|
169
|
+
const printSpy = jest.spyOn(print, 'yellow')
|
|
170
|
+
const jestAnvilReporter = new JestAnvilReporter(undefined, {
|
|
171
|
+
anvilTag: undefined,
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
jestAnvilReporter.onRunComplete(undefined, passedTestResults)
|
|
175
|
+
|
|
176
|
+
expect(printSpy).toHaveBeenCalledWith(
|
|
177
|
+
'Missing --anvilTag value! Anvil test results will be skipped.'
|
|
178
|
+
)
|
|
179
|
+
expect(generateAnvilResultsMock).not.toHaveBeenCalled()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('calls the anvil mapper', () => {
|
|
183
|
+
const anvilMapperSpy = jest.fn()
|
|
184
|
+
|
|
185
|
+
jest.mock('./anvil-results-helper', () => ({
|
|
186
|
+
anvilMapper: anvilMapperSpy,
|
|
187
|
+
generateAnvilResults: jest.fn(),
|
|
188
|
+
}))
|
|
189
|
+
const newJestAnvilReporter = require('./jest-anvil-reporter')
|
|
190
|
+
|
|
191
|
+
const jestAnvilReporter = new newJestAnvilReporter(undefined, {
|
|
192
|
+
anvilTag: 'platform',
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
jestAnvilReporter.onRunComplete(undefined, passedTestResults)
|
|
196
|
+
|
|
197
|
+
expect(anvilMapperSpy).toHaveBeenCalledWith({
|
|
198
|
+
backtrace: null,
|
|
199
|
+
description: '1 + 1 returns 2',
|
|
200
|
+
durationInSeconds: expect.any(Number),
|
|
201
|
+
error: null,
|
|
202
|
+
fileName: expect.stringContaining(
|
|
203
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js'
|
|
204
|
+
),
|
|
205
|
+
lineNumber: expect.any(Number),
|
|
206
|
+
pendingMessage: null,
|
|
207
|
+
scenarioName: 'Example test suite/1 + 1 returns 2',
|
|
208
|
+
status: 'passed',
|
|
209
|
+
tag: 'platform',
|
|
210
|
+
testType: 'unit',
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const getPackageFileContentMock = jest.fn()
|
|
2
|
+
|
|
3
|
+
jest.mock('@toptal/davinci-cli-shared', () => ({
|
|
4
|
+
files: {
|
|
5
|
+
getPackageFileContent: getPackageFileContentMock,
|
|
6
|
+
},
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
const jestArgsToCLIRules = require('./jest-args-to-cli-converters')
|
|
10
|
+
|
|
11
|
+
describe('jestArgsToCLIRules "reporters"', () => {
|
|
12
|
+
const reportersRule = jestArgsToCLIRules['reporters']
|
|
13
|
+
|
|
14
|
+
it('converts correctly arrays', () => {
|
|
15
|
+
expect(reportersRule(['reporter1', 'reporter2'])).toEqual([
|
|
16
|
+
'reporter1',
|
|
17
|
+
'reporter2',
|
|
18
|
+
])
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('converts correctly string', () => {
|
|
22
|
+
expect(reportersRule('reporter1')).toEqual(['reporter1'])
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('jestArgsToCLIRules "setupFilesAfterEnv"', () => {
|
|
27
|
+
const setupFilesAfterEnvRule = jestArgsToCLIRules['setupFilesAfterEnv']
|
|
28
|
+
|
|
29
|
+
it('takes default values from the davinci jest.config.js file', () => {
|
|
30
|
+
getPackageFileContentMock.mockReturnValueOnce({
|
|
31
|
+
setupFilesAfterEnv: ['davinci-setup-files'],
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
expect(setupFilesAfterEnvRule()).toEqual(['davinci-setup-files'])
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('merges default values with passed setup files', () => {
|
|
38
|
+
getPackageFileContentMock.mockReturnValueOnce({
|
|
39
|
+
setupFilesAfterEnv: ['davinci-setup-files'],
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
expect(setupFilesAfterEnvRule(['file1', 'file2'])).toEqual([
|
|
43
|
+
'davinci-setup-files',
|
|
44
|
+
'file1',
|
|
45
|
+
'file2',
|
|
46
|
+
])
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('merges default values with single passed setup file', () => {
|
|
50
|
+
getPackageFileContentMock.mockReturnValueOnce({
|
|
51
|
+
setupFilesAfterEnv: ['davinci-setup-files'],
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
expect(setupFilesAfterEnvRule('file1')).toEqual([
|
|
55
|
+
'davinci-setup-files',
|
|
56
|
+
'file1',
|
|
57
|
+
])
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/* eslint jest/expect-expect: ["error", { "assertFunctionNames": ["expect", "errorTest", "successTest"] }] */
|
|
2
|
+
const styledComponentsVersionCheck = require('./styled-components-version-check')
|
|
3
|
+
|
|
4
|
+
const successTest = (styledComponentsVersion, dependenciesKeys) => {
|
|
5
|
+
const packageJson = {}
|
|
6
|
+
|
|
7
|
+
dependenciesKeys.forEach(dependenciesKey => {
|
|
8
|
+
packageJson[dependenciesKey] = {
|
|
9
|
+
'styled-components': styledComponentsVersion,
|
|
10
|
+
}
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
let error = null
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
styledComponentsVersionCheck(packageJson)
|
|
17
|
+
} catch (e) {
|
|
18
|
+
error = e
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
expect(error).toBeNull()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const errorTest = (styledComponentsVersion, dependenciesKeys) => {
|
|
25
|
+
const packageJson = {}
|
|
26
|
+
|
|
27
|
+
dependenciesKeys.forEach(dependenciesKey => {
|
|
28
|
+
packageJson[dependenciesKey] = {
|
|
29
|
+
'styled-components': styledComponentsVersion,
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
let error = null
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
styledComponentsVersionCheck(packageJson)
|
|
37
|
+
} catch (e) {
|
|
38
|
+
error = e
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
expect(error).not.toBeNull()
|
|
42
|
+
expect(error.message).toContain(styledComponentsVersion)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('styled-components version check', () => {
|
|
46
|
+
describe('has wrong (^4.4.1) SC version in dependencies', () => {
|
|
47
|
+
it('should throw an error', () => {
|
|
48
|
+
errorTest('^4.4.1', ['dependencies'])
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('has correct (^5.0.1) SC version in dependencies', () => {
|
|
53
|
+
it('should NOT throw an error', () => {
|
|
54
|
+
successTest('^5.0.1', ['dependencies'])
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('has wrong (^4.4.1) SC version in devDependencies and peerDependencies', () => {
|
|
59
|
+
it('should throw an error', () => {
|
|
60
|
+
errorTest('^4.4.1', ['devDependencies', 'peerDependencies'])
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('has correct (^5.0.1) SC version in devDependencies and peerDependencies', () => {
|
|
65
|
+
it('should NOT throw an error', () => {
|
|
66
|
+
successTest('^5.0.1', ['devDependencies', 'peerDependencies'])
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe('has wrong (^4.4.1) SC version in devDependencies', () => {
|
|
71
|
+
it('should throw an error', () => {
|
|
72
|
+
errorTest('^4.4.1', ['devDependencies'])
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('has correct (^5.0.1) SC version in devDependencies', () => {
|
|
77
|
+
it('should NOT throw an error', () => {
|
|
78
|
+
successTest('^5.0.1', ['devDependencies'])
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const toJestCLIArguments = require('./to-jest-cli-arguments')
|
|
2
|
+
|
|
3
|
+
const EXAMPLE_REPORTER = 'some-jest-reporter'
|
|
4
|
+
const ARGS_TO_CLI_RESULT = [EXAMPLE_REPORTER]
|
|
5
|
+
|
|
6
|
+
jest.mock('./jest-args-to-cli-converters.js', () => ({
|
|
7
|
+
reporters: () => ARGS_TO_CLI_RESULT,
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
describe('toJestCLIArguments', () => {
|
|
11
|
+
it('converts boolean strings to booleans correctly', () => {
|
|
12
|
+
expect(
|
|
13
|
+
toJestCLIArguments({
|
|
14
|
+
cache: 'false',
|
|
15
|
+
ci: 'true',
|
|
16
|
+
})
|
|
17
|
+
).toEqual({
|
|
18
|
+
cache: false,
|
|
19
|
+
ci: true,
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('converts some rules by using args-to-cli rules', () => {
|
|
24
|
+
expect(
|
|
25
|
+
toJestCLIArguments({
|
|
26
|
+
reporters: EXAMPLE_REPORTER,
|
|
27
|
+
})
|
|
28
|
+
).toEqual({
|
|
29
|
+
reporters: ARGS_TO_CLI_RESULT,
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
})
|