diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/helper.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/helper.ts index 22d5e2c772..da1df76500 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/helper.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/helper.ts @@ -101,7 +101,7 @@ class Helper { } public runForAllSupportedSchemes(suiteFactory: TestSuiteFactory): void { - Object.keys(this.portPerScheme).forEach(scheme => suiteFactory(scheme, this.portPerScheme[scheme])); + Object.entries(this.portPerScheme).forEach(([scheme, port]) => suiteFactory(scheme, port)); } public verifyResponse(status: number, regex: string | RegExp = /^/): VerifyCmdResultFn { diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/nginx.e2e.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/nginx.e2e.ts index 4a58bad9f2..8fe35eb81e 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/nginx.e2e.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/nginx.e2e.ts @@ -15,7 +15,7 @@ describe(`nginx`, () => { afterEach(() => h.cleanUp()); - it('should redirect HTTP to HTTPS', done => { + it('should redirect HTTP to HTTPS', async () => { const httpHost = `${AIO_NGINX_HOSTNAME}:${AIO_NGINX_PORT_HTTP}`; const httpsHost = `${AIO_NGINX_HOSTNAME}:${AIO_NGINX_PORT_HTTPS}`; const urlMap = { @@ -24,16 +24,15 @@ describe(`nginx`, () => { [`http://foo.${httpHost}/`]: `https://foo.${httpsHost}/`, }; - const verifyRedirection = (httpUrl: string) => h.runCmd(`curl -i ${httpUrl}`).then(result => { + const verifyRedirection = async (fromUrl: string, toUrl: string) => { + const result = await h.runCmd(`curl -i ${fromUrl}`); h.verifyResponse(307)(result); const headers = result.stdout.split(/(?:\r?\n){2,}/)[0]; - expect(headers).toContain(`Location: ${urlMap[httpUrl]}`); - }); + expect(headers).toContain(`Location: ${toUrl}`); + }; - Promise. - all(Object.keys(urlMap).map(verifyRedirection)). - then(done); + await Promise.all(Object.entries(urlMap).map(urls => verifyRedirection(...urls))); }); @@ -62,15 +61,15 @@ describe(`nginx`, () => { }); - it('should return /index.html', done => { + it('should return /index.html', async () => { const origin = `${scheme}://pr${pr}-${shortSha9}.${host}`; const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /index\\.html$`); - Promise.all([ + await Promise.all([ h.runCmd(`curl -iL ${origin}/index.html`).then(h.verifyResponse(200, bodyRegex)), h.runCmd(`curl -iL ${origin}/`).then(h.verifyResponse(200, bodyRegex)), h.runCmd(`curl -iL ${origin}`).then(h.verifyResponse(200, bodyRegex)), - ]).then(done); + ]); }); @@ -90,12 +89,11 @@ describe(`nginx`, () => { }); - it('should return /foo/bar.js', done => { + it('should return /foo/bar.js', async () => { const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /foo/bar\\.js$`); - h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/bar.js`). - then(h.verifyResponse(200, bodyRegex)). - then(done); + await h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/bar.js`). + then(h.verifyResponse(200, bodyRegex)); }); @@ -111,47 +109,46 @@ describe(`nginx`, () => { }); - it('should respond with 403 for directories', done => { - Promise.all([ + it('should respond with 403 for directories', async () => { + await Promise.all([ h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/`).then(h.verifyResponse(403)), h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo`).then(h.verifyResponse(403)), - ]).then(done); + ]); }); - it('should respond with 404 for unknown paths to files', done => { - h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/baz.css`). - then(h.verifyResponse(404)). - then(done); + it('should respond with 404 for unknown paths to files', async () => { + await h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/baz.css`). + then(h.verifyResponse(404)); }); - it('should rewrite to \'index.html\' for unknown paths that don\'t look like files', done => { + it('should rewrite to \'index.html\' for unknown paths that don\'t look like files', async () => { const origin = `${scheme}://pr${pr}-${shortSha9}.${host}`; const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /index\\.html$`); - Promise.all([ + await Promise.all([ h.runCmd(`curl -iL ${origin}/foo/baz`).then(h.verifyResponse(200, bodyRegex)), h.runCmd(`curl -iL ${origin}/foo/baz/`).then(h.verifyResponse(200, bodyRegex)), - ]).then(done); + ]); }); - it('should respond with 404 for unknown PRs/SHAs', done => { + it('should respond with 404 for unknown PRs/SHAs', async () => { const otherPr = 54321; const otherShortSha = computeShortSha('8'.repeat(40)); - Promise.all([ + await Promise.all([ h.runCmd(`curl -iL ${scheme}://pr${pr}9-${shortSha9}.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://pr${otherPr}-${shortSha9}.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}9.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://pr${pr}-${otherShortSha}.${host}`).then(h.verifyResponse(404)), - ]).then(done); + ]); }); - it('should respond with 404 if the subdomain format is wrong', done => { - Promise.all([ + it('should respond with 404 if the subdomain format is wrong', async () => { + await Promise.all([ h.runCmd(`curl -iL ${scheme}://xpr${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://prx${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://xx${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)), @@ -160,26 +157,25 @@ describe(`nginx`, () => { h.runCmd(`curl -iL ${scheme}://${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://pr${pr}${shortSha9}.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://pr${pr}_${shortSha9}.${host}`).then(h.verifyResponse(404)), - ]).then(done); + ]); }); - it('should reject PRs with leading zeros', done => { - h.runCmd(`curl -iL ${scheme}://pr0${pr}-${shortSha9}.${host}`). - then(h.verifyResponse(404)). - then(done); + it('should reject PRs with leading zeros', async () => { + await h.runCmd(`curl -iL ${scheme}://pr0${pr}-${shortSha9}.${host}`). + then(h.verifyResponse(404)); }); - it('should accept SHAs with leading zeros (but not trim the zeros)', done => { + it('should accept SHAs with leading zeros (but not trim the zeros)', async () => { const bodyRegex9 = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /index\\.html$`); const bodyRegex0 = new RegExp(`^PR: ${pr} | SHA: ${sha0} | File: /index\\.html$`); - Promise.all([ + await Promise.all([ h.runCmd(`curl -iL ${scheme}://pr${pr}-0${shortSha9}.${host}`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}`).then(h.verifyResponse(200, bodyRegex9)), h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha0}.${host}`).then(h.verifyResponse(200, bodyRegex0)), - ]).then(done); + ]); }); }); @@ -231,23 +227,23 @@ describe(`nginx`, () => { describe(`${host}/health-check`, () => { - it('should respond with 200', done => { - Promise.all([ + it('should respond with 200', async () => { + await Promise.all([ h.runCmd(`curl -iL ${scheme}://${host}/health-check`).then(h.verifyResponse(200)), h.runCmd(`curl -iL ${scheme}://${host}/health-check/`).then(h.verifyResponse(200)), - ]).then(done); + ]); }); - it('should respond with 404 if the path does not match exactly', done => { - Promise.all([ + it('should respond with 404 if the path does not match exactly', async () => { + await Promise.all([ h.runCmd(`curl -iL ${scheme}://${host}/health-check/foo`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://${host}/health-check-foo`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://${host}/health-checknfoo`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://${host}/foo/health-check`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://${host}/foo-health-check`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${scheme}://${host}/foonhealth-check`).then(h.verifyResponse(404)), - ]).then(done); + ]); }); }); @@ -291,29 +287,28 @@ describe(`nginx`, () => { describe(`${host}/circle-build`, () => { - it('should disallow non-POST requests', done => { + it('should disallow non-POST requests', async () => { const url = `${scheme}://${host}/circle-build`; - Promise.all([ + await Promise.all([ h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse(405)), h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse(405)), h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse(405)), h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse(405)), - ]).then(done); + ]); }); - it('should pass requests through to the preview server', done => { - h.runCmd(`curl -iLX POST ${scheme}://${host}/circle-build`). - then(h.verifyResponse(400, /Incorrect body content. Expected JSON/)). - then(done); + it('should pass requests through to the preview server', async () => { + await h.runCmd(`curl -iLX POST ${scheme}://${host}/circle-build`). + then(h.verifyResponse(400, /Incorrect body content. Expected JSON/)); }); - it('should respond with 404 for unknown paths', done => { + it('should respond with 404 for unknown paths', async () => { const cmdPrefix = `curl -iLX POST ${scheme}://${host}`; - Promise.all([ + await Promise.all([ h.runCmd(`${cmdPrefix}/foo/circle-build/`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/foo-circle-build/`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/fooncircle-build/`).then(h.verifyResponse(404)), @@ -322,7 +317,7 @@ describe(`nginx`, () => { h.runCmd(`${cmdPrefix}/circle-buildnfoo/`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/circle-build/pr`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/circle-build/42`).then(h.verifyResponse(404)), - ]).then(done); + ]); }); }); @@ -332,38 +327,33 @@ describe(`nginx`, () => { const url = `${scheme}://${host}/pr-updated`; - it('should disallow non-POST requests', done => { - Promise.all([ + it('should disallow non-POST requests', async () => { + await Promise.all([ h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse(405)), h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse(405)), h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse(405)), h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse(405)), - ]).then(done); + ]); }); - it('should pass requests through to the preview server', done => { - const cmdPrefix = `curl -iLX POST --header "Content-Type: application/json"`; - - const cmd1 = `${cmdPrefix} ${url}`; - - Promise.all([ - h.runCmd(cmd1).then(h.verifyResponse(400, /Missing or empty 'number' field/)), - ]).then(done); + it('should pass requests through to the preview server', async () => { + await h.runCmd(`curl -iLX POST --header "Content-Type: application/json" ${url}`). + then(h.verifyResponse(400, /Missing or empty 'number' field/)); }); - it('should respond with 404 for unknown paths', done => { + it('should respond with 404 for unknown paths', async () => { const cmdPrefix = `curl -iLX POST ${scheme}://${host}`; - Promise.all([ + await Promise.all([ h.runCmd(`${cmdPrefix}/foo/pr-updated`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/foo-pr-updated`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/foonpr-updated`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/pr-updated/foo`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/pr-updated-foo`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/pr-updatednfoo`).then(h.verifyResponse(404)), - ]).then(done); + ]); }); }); @@ -374,7 +364,7 @@ describe(`nginx`, () => { beforeEach(() => { ['index.html', 'foo.js', 'foo/index.html'].forEach(relFilePath => { const absFilePath = path.join(AIO_BUILDS_DIR, relFilePath); - return h.writeFile(absFilePath, {content: `File: /${relFilePath}`}); + h.writeFile(absFilePath, {content: `File: /${relFilePath}`}); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/preview-server.e2e.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/preview-server.e2e.ts index b7134cd799..72a9cc3264 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/preview-server.e2e.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/lib/verify-setup/preview-server.e2e.ts @@ -105,9 +105,9 @@ describe('preview-server', () => { describe(`${host}/circle-build`, () => { - const curl = makeCurl(`${host}/circle-build`); + it('should disallow non-POST requests', async () => { const bodyRegex = /^Unknown resource/; @@ -189,8 +189,7 @@ describe('preview-server', () => { }); it('should respond with 201 if a new public build is created', async () => { - await curl(payload(BuildNums.TRUST_CHECK_ACTIVE_TRUSTED_USER)) - .then(h.verifyResponse(201)); + await curl(payload(BuildNums.TRUST_CHECK_ACTIVE_TRUSTED_USER)).then(h.verifyResponse(201)); expect({ prNum: PrNums.TRUST_CHECK_ACTIVE_TRUSTED_USER }).toExistAsABuild(); }); @@ -364,23 +363,23 @@ describe('preview-server', () => { describe(`${host}/health-check`, () => { - it('should respond with 200', done => { - Promise.all([ + it('should respond with 200', async () => { + await Promise.all([ h.runCmd(`curl -iL ${host}/health-check`).then(h.verifyResponse(200)), h.runCmd(`curl -iL ${host}/health-check/`).then(h.verifyResponse(200)), - ]).then(done); + ]); }); - it('should respond with 404 if the path does not match exactly', done => { - Promise.all([ + it('should respond with 404 if the path does not match exactly', async () => { + await Promise.all([ h.runCmd(`curl -iL ${host}/health-check/foo`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${host}/health-check-foo`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${host}/health-checknfoo`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${host}/foo/health-check`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${host}/foo-health-check`).then(h.verifyResponse(404)), h.runCmd(`curl -iL ${host}/foonhealth-check`).then(h.verifyResponse(404)), - ]).then(done); + ]); }); }); @@ -426,18 +425,18 @@ describe('preview-server', () => { }); - it('should respond with 404 for unknown paths', done => { + it('should respond with 404 for unknown paths', async () => { const mockPayload = JSON.stringify({number: 1}); // MockExternalApiFlags.TRUST_CHECK_ACTIVE_TRUSTED_USER }); const cmdPrefix = `curl -iLX POST --data "${mockPayload}" ${host}`; - Promise.all([ + await Promise.all([ h.runCmd(`${cmdPrefix}/foo/pr-updated`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/foo-pr-updated`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/foonpr-updated`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/pr-updated/foo`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/pr-updated-foo`).then(h.verifyResponse(404)), h.runCmd(`${cmdPrefix}/pr-updatednfoo`).then(h.verifyResponse(404)), - ]).then(done); + ]); }); @@ -551,10 +550,10 @@ describe('preview-server', () => { describe(`${host}/*`, () => { - it('should respond with 404 for requests to unknown URLs', done => { + it('should respond with 404 for requests to unknown URLs', async () => { const bodyRegex = /^Unknown resource/; - Promise.all([ + await Promise.all([ h.runCmd(`curl -iL ${host}/index.html`).then(h.verifyResponse(404, bodyRegex)), h.runCmd(`curl -iL ${host}/`).then(h.verifyResponse(404, bodyRegex)), h.runCmd(`curl -iL ${host}`).then(h.verifyResponse(404, bodyRegex)), @@ -562,7 +561,7 @@ describe('preview-server', () => { h.runCmd(`curl -iLX POST ${host}`).then(h.verifyResponse(404, bodyRegex)), h.runCmd(`curl -iLX PATCH ${host}`).then(h.verifyResponse(404, bodyRegex)), h.runCmd(`curl -iLX DELETE ${host}`).then(h.verifyResponse(404, bodyRegex)), - ]).then(done); + ]); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/clean-up/build-cleaner.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/clean-up/build-cleaner.spec.ts index 5b530d0f3e..df3a4d969d 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/clean-up/build-cleaner.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/clean-up/build-cleaner.spec.ts @@ -76,22 +76,18 @@ describe('BuildCleaner', () => { let cleanerRemoveUnnecessaryDownloadsSpy: jasmine.Spy; beforeEach(() => { - cleanerGetExistingBuildNumbersSpy = spyOn(cleaner, 'getExistingBuildNumbers') - .and.callFake(() => Promise.resolve(EXISTING_BUILDS)); - cleanerGetOpenPrNumbersSpy = spyOn(cleaner, 'getOpenPrNumbers') - .and.callFake(() => Promise.resolve(OPEN_PRS)); - cleanerGetExistingDownloadsSpy = spyOn(cleaner, 'getExistingDownloads') - .and.callFake(() => Promise.resolve(EXISTING_DOWNLOADS)); + cleanerGetExistingBuildNumbersSpy = spyOn(cleaner, 'getExistingBuildNumbers').and.resolveTo(EXISTING_BUILDS); + cleanerGetOpenPrNumbersSpy = spyOn(cleaner, 'getOpenPrNumbers').and.resolveTo(OPEN_PRS); + cleanerGetExistingDownloadsSpy = spyOn(cleaner, 'getExistingDownloads').and.resolveTo(EXISTING_DOWNLOADS); cleanerRemoveUnnecessaryBuildsSpy = spyOn(cleaner, 'removeUnnecessaryBuilds'); cleanerRemoveUnnecessaryDownloadsSpy = spyOn(cleaner, 'removeUnnecessaryDownloads'); - }); it('should return a promise', async () => { const promise = cleaner.cleanUp(); - expect(promise).toEqual(jasmine.any(Promise)); + expect(promise).toBeInstanceOf(Promise); // Do not complete the test and release the spies synchronously, to avoid running the actual implementations. await promise; @@ -174,7 +170,7 @@ describe('BuildCleaner', () => { it('should return a promise', () => { - expect(promise).toEqual(jasmine.any(Promise)); + expect(promise).toBeInstanceOf(Promise); }); @@ -184,43 +180,27 @@ describe('BuildCleaner', () => { }); - it('should reject if an error occurs while getting the files', done => { - promise.catch(err => { - expect(err).toBe('Test'); - done(); - }); - + it('should reject if an error occurs while getting the files', async () => { readdirCb('Test'); + await expectAsync(promise).toBeRejectedWith('Test'); }); - it('should resolve with the returned files (as numbers)', done => { - promise.then(result => { - expect(result).toEqual([12, 34, 56]); - done(); - }); - + it('should resolve with the returned files (as numbers)', async () => { readdirCb(null, ['12', '34', '56']); + await expectAsync(promise).toBeResolvedTo([12, 34, 56]); }); - it('should remove `HIDDEN_DIR_PREFIX` from the filenames', done => { - promise.then(result => { - expect(result).toEqual([12, 34, 56]); - done(); - }); - + it('should remove `HIDDEN_DIR_PREFIX` from the filenames', async () => { readdirCb(null, [`${HIDDEN_DIR_PREFIX}12`, '34', `${HIDDEN_DIR_PREFIX}56`]); + await expectAsync(promise).toBeResolvedTo([12, 34, 56]); }); - it('should ignore files with non-numeric (or zero) names', done => { - promise.then(result => { - expect(result).toEqual([12, 34, 56]); - done(); - }); - + it('should ignore files with non-numeric (or zero) names', async () => { readdirCb(null, ['12', 'foo', '34', 'bar', '56', '000']); + await expectAsync(promise).toBeResolvedTo([12, 34, 56]); }); }); @@ -240,7 +220,7 @@ describe('BuildCleaner', () => { it('should return a promise', () => { - expect(promise).toEqual(jasmine.any(Promise)); + expect(promise).toBeInstanceOf(Promise); }); @@ -249,23 +229,15 @@ describe('BuildCleaner', () => { }); - it('should reject if an error occurs while fetching PRs', done => { - promise.catch(err => { - expect(err).toBe('Test'); - done(); - }); - + it('should reject if an error occurs while fetching PRs', async () => { prDeferred.reject('Test'); + await expectAsync(promise).toBeRejectedWith('Test'); }); - it('should resolve with the numbers of the fetched PRs', done => { - promise.then(prNumbers => { - expect(prNumbers).toEqual([1, 2, 3]); - done(); - }); - + it('should resolve with the numbers of the fetched PRs', async () => { prDeferred.resolve([{id: 0, number: 1}, {id: 1, number: 2}, {id: 2, number: 3}]); + await expectAsync(promise).toBeResolvedTo([1, 2, 3]); }); }); @@ -285,7 +257,7 @@ describe('BuildCleaner', () => { it('should return a promise', () => { - expect(promise).toEqual(jasmine.any(Promise)); + expect(promise).toBeInstanceOf(Promise); }); @@ -295,33 +267,21 @@ describe('BuildCleaner', () => { }); - it('should reject if an error occurs while getting the files', done => { - promise.catch(err => { - expect(err).toBe('Test'); - done(); - }); - + it('should reject if an error occurs while getting the files', async () => { readdirCb('Test'); + await expectAsync(promise).toBeRejectedWith('Test'); }); - it('should resolve with the returned file names', done => { - promise.then(result => { - expect(result).toEqual(EXISTING_DOWNLOADS); - done(); - }); - + it('should resolve with the returned file names', async () => { readdirCb(null, EXISTING_DOWNLOADS); + await expectAsync(promise).toBeResolvedTo(EXISTING_DOWNLOADS); }); - it('should ignore files that do not match the artifactPath', done => { - promise.then(result => { - expect(result).toEqual(['10-ABCDEF-build.zip', '30-FFFFFFF-build.zip']); - done(); - }); - + it('should ignore files that do not match the artifactPath', async () => { readdirCb(null, ['10-ABCDEF-build.zip', '20-AAAAAAA-otherfile.zip', '30-FFFFFFF-build.zip']); + await expectAsync(promise).toBeResolvedTo(['10-ABCDEF-build.zip', '30-FFFFFFF-build.zip']); }); }); @@ -339,7 +299,7 @@ describe('BuildCleaner', () => { }); - it('should test if the directory exists (and return if is does not)', () => { + it('should test if the directory exists (and return if it does not)', () => { shellTestSpy.and.returnValue(false); cleaner.removeDir('/foo/bar'); @@ -356,22 +316,19 @@ describe('BuildCleaner', () => { it('should make the directory and its content writable before removing', () => { - shellRmSpy.and.callFake(() => expect(shellChmodSpy).toHaveBeenCalledWith('-R', 'a+w', '/foo/bar')); cleaner.removeDir('/foo/bar'); + expect(shellChmodSpy).toHaveBeenCalledBefore(shellRmSpy); + expect(shellChmodSpy).toHaveBeenCalledWith('-R', 'a+w', '/foo/bar'); expect(shellRmSpy).toHaveBeenCalled(); }); it('should catch errors and log them', () => { - shellRmSpy.and.callFake(() => { - // tslint:disable-next-line: no-string-throw - throw 'Test'; - }); - + shellRmSpy.and.throwError('Test'); cleaner.removeDir('/foo/bar'); - expect(loggerErrorSpy).toHaveBeenCalledWith('ERROR: Unable to remove \'/foo/bar\' due to:', 'Test'); + expect(loggerErrorSpy).toHaveBeenCalledWith('ERROR: Unable to remove \'/foo/bar\' due to:', new Error('Test')); }); }); @@ -424,7 +381,7 @@ describe('BuildCleaner', () => { expect(cleanerRemoveDirSpy).toHaveBeenCalledTimes(0); cleanerRemoveDirSpy.calls.reset(); - (cleaner as any).removeUnnecessaryBuilds([1, 2, 3, 4], []); + cleaner.removeUnnecessaryBuilds([1, 2, 3, 4], []); expect(cleanerRemoveDirSpy).toHaveBeenCalledTimes(8); expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(normalize('/foo/bar/1')); expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(normalize('/foo/bar/2')); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/circleci-api.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/circleci-api.spec.ts index 7bd3b5b820..7e9defb8db 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/circleci-api.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/circleci-api.spec.ts @@ -45,25 +45,15 @@ describe('CircleCIApi', () => { const errorMessage = 'Invalid request'; const request = nock(BASE_URL).get(`/${buildNum}?circle-token=${TOKEN}`); - try { - request.replyWithError(errorMessage); - await api.getBuildInfo(buildNum); - throw new Error('Exception Expected'); - } catch (err) { - expect(err.message).toEqual( + request.replyWithError(errorMessage); + await expectAsync(api.getBuildInfo(buildNum)).toBeRejectedWithError( `CircleCI build info request failed ` + `(request to ${BASE_URL}/${buildNum}?circle-token=${TOKEN} failed, reason: ${errorMessage})`); - } - try { - request.reply(404, errorMessage); - await api.getBuildInfo(buildNum); - throw new Error('Exception Expected'); - } catch (err) { - expect(err.message).toEqual( + request.reply(404, errorMessage); + await expectAsync(api.getBuildInfo(buildNum)).toBeRejectedWithError( `CircleCI build info request failed ` + `(request to ${BASE_URL}/${buildNum}?circle-token=${TOKEN} failed, reason: ${errorMessage})`); - } }); }); @@ -78,8 +68,7 @@ describe('CircleCIApi', () => { .get(`/${buildNum}/artifacts?circle-token=${TOKEN}`) .reply(200, [artifact0, artifact1, artifact2]); - const artifactUrl = await api.getBuildArtifactUrl(buildNum, 'some/path/1'); - expect(artifactUrl).toEqual('https://url/1'); + await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/1')).toBeResolvedTo('https://url/1'); request.done(); }); @@ -90,25 +79,15 @@ describe('CircleCIApi', () => { const errorMessage = 'Invalid request'; const request = nock(BASE_URL).get(`/${buildNum}/artifacts?circle-token=${TOKEN}`); - try { - request.replyWithError(errorMessage); - await api.getBuildArtifactUrl(buildNum, 'some/path/1'); - throw new Error('Exception Expected'); - } catch (err) { - expect(err.message).toEqual( + request.replyWithError(errorMessage); + await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/1')).toBeRejectedWithError( `CircleCI artifact URL request failed ` + `(request to ${BASE_URL}/${buildNum}/artifacts?circle-token=${TOKEN} failed, reason: ${errorMessage})`); - } - try { - request.reply(404, errorMessage); - await api.getBuildArtifactUrl(buildNum, 'some/path/1'); - throw new Error('Exception Expected'); - } catch (err) { - expect(err.message).toEqual( + request.reply(404, errorMessage); + await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/1')).toBeRejectedWithError( `CircleCI artifact URL request failed ` + `(request to ${BASE_URL}/${buildNum}/artifacts?circle-token=${TOKEN} failed, reason: ${errorMessage})`); - } }); it('should throw an error if the response does not contain the specified artifact', async () => { @@ -121,14 +100,9 @@ describe('CircleCIApi', () => { .get(`/${buildNum}/artifacts?circle-token=${TOKEN}`) .reply(200, [artifact0, artifact1, artifact2]); - try { - await api.getBuildArtifactUrl(buildNum, 'some/path/3'); - throw new Error('Exception Expected'); - } catch (err) { - expect(err.message).toEqual( + await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/3')).toBeRejectedWithError( `CircleCI artifact URL request failed ` + `(Missing artifact (some/path/3) for CircleCI build: ${buildNum})`); - } }); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-api.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-api.spec.ts index 3b841f92fc..61df1ad4b7 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-api.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-api.spec.ts @@ -118,7 +118,7 @@ describe('GithubApi', () => { it('should return a promise', () => { - expect((api as any).getPaginated()).toEqual(jasmine.any(Promise)); + expect((api as any).getPaginated()).toBeInstanceOf(Promise); }); @@ -131,45 +131,30 @@ describe('GithubApi', () => { }); - it('should reject if the request fails', done => { - (api as any).getPaginated('/foo/bar').catch((err: any) => { - expect(err).toBe('Test'); - done(); - }); - + it('should reject if the request fails', async () => { + const responsePromise = (api as any).getPaginated('/foo/bar'); deferreds[0].reject('Test'); + + await expectAsync(responsePromise).toBeRejectedWith('Test'); }); - it('should resolve with the returned items', done => { + it('should resolve with the returned items', async () => { const items = [{id: 1}, {id: 2}]; - - (api as any).getPaginated('/foo/bar').then((data: any) => { - expect(data).toEqual(items); - done(); - }); - + const responsePromise = (api as any).getPaginated('/foo/bar'); deferreds[0].resolve(items); + + await expectAsync(responsePromise).toBeResolvedTo(items); }); - it('should iteratively call \'get()\' to fetch all items', done => { + it('should iteratively call \'get()\' to fetch all items', async () => { // Create an array or 250 objects. - const allItems = '.'.repeat(250).split('').map((_, i) => ({id: i})); + const allItems = new Array(250).fill(null).map((_, i) => ({id: i})); const apiGetSpy = api.get as jasmine.Spy; + const paramsForPage = (page: number) => ({baz: 'qux', page, per_page: 100}); - (api as any).getPaginated('/foo/bar', {baz: 'qux'}).then((data: any) => { - const paramsForPage = (page: number) => ({baz: 'qux', page, per_page: 100}); - - expect(apiGetSpy).toHaveBeenCalledTimes(3); - expect(apiGetSpy.calls.argsFor(0)).toEqual(['/foo/bar', paramsForPage(1)]); - expect(apiGetSpy.calls.argsFor(1)).toEqual(['/foo/bar', paramsForPage(2)]); - expect(apiGetSpy.calls.argsFor(2)).toEqual(['/foo/bar', paramsForPage(3)]); - - expect(data).toEqual(allItems); - - done(); - }); + const responsePromise = (api as any).getPaginated('/foo/bar', {baz: 'qux'}); deferreds[0].resolve(allItems.slice(0, 100)); setTimeout(() => { @@ -178,6 +163,13 @@ describe('GithubApi', () => { deferreds[2].resolve(allItems.slice(200)); }, 0); }, 0); + + await expectAsync(responsePromise).toBeResolvedTo(allItems); + + expect(apiGetSpy).toHaveBeenCalledTimes(3); + expect(apiGetSpy.calls.argsFor(0)).toEqual(['/foo/bar', paramsForPage(1)]); + expect(apiGetSpy.calls.argsFor(1)).toEqual(['/foo/bar', paramsForPage(2)]); + expect(apiGetSpy.calls.argsFor(2)).toEqual(['/foo/bar', paramsForPage(3)]); }); }); @@ -218,7 +210,7 @@ describe('GithubApi', () => { describe('request()', () => { it('should return a promise', () => { nock('https://api.github.com').get('/').reply(200); - expect((api as any).request()).toEqual(jasmine.any(Promise)); + expect((api as any).request()).toBeInstanceOf(Promise); }); @@ -247,9 +239,8 @@ describe('GithubApi', () => { nock('https://api.github.com') .intercept('/path', 'method') .replyWithError('Test'); - let message = 'Failed to reject error'; - await (api as any).request('method', '/path').catch((err: any) => message = err.message); - expect(message).toEqual('Test'); + + await expectAsync((api as any).request('method', '/path')).toBeRejectedWithError('Test'); }); @@ -263,81 +254,69 @@ describe('GithubApi', () => { }); - it('should reject if response statusCode is <200', done => { + it('should reject if response statusCode is <200', async () => { const requestHandler = nock('https://api.github.com') .intercept('/path', 'method') .reply(199); + const responsePromise = (api as any).request('method', '/path'); + + await expectAsync(responsePromise).toBeRejectedWith(jasmine.stringMatching('failed')); + await expectAsync(responsePromise).toBeRejectedWith(jasmine.stringMatching('status: 199')); - (api as any).request('method', '/path') - .catch((err: string) => { - expect(err).toContain('failed'); - expect(err).toContain('status: 199'); - done(); - }); requestHandler.done(); }); - it('should reject if response statusCode is >=400', done => { + it('should reject if response statusCode is >=400', async () => { const requestHandler = nock('https://api.github.com') .intercept('/path', 'method') .reply(400); + const responsePromise = (api as any).request('method', '/path'); + + await expectAsync(responsePromise).toBeRejectedWith(jasmine.stringMatching('failed')); + await expectAsync(responsePromise).toBeRejectedWith(jasmine.stringMatching('status: 400')); - (api as any).request('method', '/path') - .catch((err: string) => { - expect(err).toContain('failed'); - expect(err).toContain('status: 400'); - done(); - }); requestHandler.done(); }); - it('should include the response text in the rejection message', done => { + it('should include the response text in the rejection message', async () => { const requestHandler = nock('https://api.github.com') .intercept('/path', 'method') .reply(500, 'Test'); + const responsePromise = (api as any).request('method', '/path'); + + await expectAsync(responsePromise).toBeRejectedWith(jasmine.stringMatching('Test')); - (api as any).request('method', '/path') - .catch((err: string) => { - expect(err).toContain('Test'); - done(); - }); requestHandler.done(); }); - it('should resolve if returned statusCode is >=200 and <400', done => { + it('should resolve if returned statusCode is >=200 and <400', async () => { const requestHandler = nock('https://api.github.com') .intercept('/path', 'method') .reply(200); - (api as any).request('method', '/path').then(done); + await expectAsync((api as any).request('method', '/path')).toBeResolved(); requestHandler.done(); }); - it('should parse the response body into an object using \'JSON.parse\'', done => { + it('should parse the response body into an object using \'JSON.parse\'', async () => { const requestHandler = nock('https://api.github.com') .intercept('/path', 'method') .reply(300, '{"foo": "bar"}'); - (api as any).request('method', '/path').then((data: any) => { - expect(data).toEqual({foo: 'bar'}); - done(); - }); + await expectAsync((api as any).request('method', '/path')).toBeResolvedTo({foo: 'bar'}); requestHandler.done(); }); - it('should reject if the response text is malformed JSON', done => { + it('should reject if the response text is malformed JSON', async () => { const requestHandler = nock('https://api.github.com') .intercept('/path', 'method') .reply(300, '}'); - (api as any).request('method', '/path').catch((err: any) => { - expect(err).toEqual(jasmine.any(SyntaxError)); - done(); - }); + await expectAsync((api as any).request('method', '/path')).toBeRejectedWithError(SyntaxError); requestHandler.done(); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-pull-requests.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-pull-requests.spec.ts index a22d481e1a..c79218a0cb 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-pull-requests.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-pull-requests.spec.ts @@ -53,21 +53,15 @@ describe('GithubPullRequests', () => { }); - it('should reject if the request fails', done => { - githubApi.post.and.callFake(() => Promise.reject('Test')); - prs.addComment(42, 'body').catch(err => { - expect(err).toBe('Test'); - done(); - }); + it('should reject if the request fails', async () => { + githubApi.post.and.rejectWith('Test'); + await expectAsync(prs.addComment(42, 'body')).toBeRejectedWith('Test'); }); - it('should resolve with the data from the Github POST', done => { + it('should resolve with the data from the Github POST', async () => { githubApi.post.and.resolveTo('Test'); - prs.addComment(42, 'body').then(data => { - expect(data).toBe('Test'); - done(); - }); + await expectAsync(prs.addComment(42, 'body')).toBeResolvedTo('Test'); }); }); @@ -87,13 +81,11 @@ describe('GithubPullRequests', () => { }); - it('should resolve with the data returned from GitHub', done => { + it('should resolve with the data returned from GitHub', async () => { const expected: any = {number: 42}; - githubApi.get.and.callFake(() => Promise.resolve(expected)); - prs.fetch(42).then(data => { - expect(data).toEqual(expected); - done(); - }); + githubApi.get.and.resolveTo(expected); + + await expectAsync(prs.fetch(42)).toBeResolvedTo(expected); }); }); @@ -152,13 +144,11 @@ describe('GithubPullRequests', () => { }); - it('should resolve with the data returned from GitHub', done => { + it('should resolve with the data returned from GitHub', async () => { const expected: any = [{sha: 'ABCDE', filename: 'a/b/c'}, {sha: '12345', filename: 'x/y/z'}]; - githubApi.getPaginated.and.callFake(() => Promise.resolve(expected)); - prs.fetchFiles(42).then(data => { - expect(data).toEqual(expected); - done(); - }); + githubApi.getPaginated.and.resolveTo(expected); + + await expectAsync(prs.fetchFiles(42)).toBeResolvedTo(expected); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-teams.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-teams.spec.ts index 96d79585bf..d8fa2a4d7b 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-teams.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/common/github-teams.spec.ts @@ -16,6 +16,7 @@ describe('GithubTeams', () => { expect(() => new GithubTeams(githubApi, '')). toThrowError('Missing or empty required parameter \'githubOrg\'!'); }); + }); @@ -57,98 +58,75 @@ describe('GithubTeams', () => { it('should return a promise', () => { githubApi.get.and.resolveTo(); const promise = teams.isMemberById('user', [1]); - expect(promise).toEqual(jasmine.any(Promise)); + expect(promise).toBeInstanceOf(Promise); }); - it('should resolve with false if called with an empty array', done => { - teams.isMemberById('user', []).then(isMember => { - expect(isMember).toBe(false); - expect(githubApi.get).not.toHaveBeenCalled(); - done(); - }); + it('should resolve with false if called with an empty array', async () => { + await expectAsync(teams.isMemberById('user', [])).toBeResolvedTo(false); + expect(githubApi.get).not.toHaveBeenCalled(); }); - it('should call \'get()\' with the correct pathname', done => { + it('should call \'get()\' with the correct pathname', async () => { githubApi.get.and.resolveTo(); - teams.isMemberById('user', [1]).then(() => { - expect(githubApi.get).toHaveBeenCalledWith('/teams/1/memberships/user'); - done(); - }); + await teams.isMemberById('user', [1]); + + expect(githubApi.get).toHaveBeenCalledWith('/teams/1/memberships/user'); }); - it('should resolve with false if \'get()\' rejects', done => { - githubApi.get.and.callFake(() => Promise.reject(null)); - teams.isMemberById('user', [1]).then(isMember => { - expect(isMember).toBe(false); - expect(githubApi.get).toHaveBeenCalled(); - done(); - }); + it('should resolve with false if \'get()\' rejects', async () => { + githubApi.get.and.rejectWith(null); + + await expectAsync(teams.isMemberById('user', [1])).toBeResolvedTo(false); + expect(githubApi.get).toHaveBeenCalled(); }); - it('should resolve with false if the membership is not active', done => { + it('should resolve with false if the membership is not active', async () => { githubApi.get.and.resolveTo({state: 'pending'}); - teams.isMemberById('user', [1]).then(isMember => { - expect(isMember).toBe(false); - expect(githubApi.get).toHaveBeenCalled(); - done(); - }); + + await expectAsync(teams.isMemberById('user', [1])).toBeResolvedTo(false); + expect(githubApi.get).toHaveBeenCalled(); }); - it('should resolve with true if the membership is active', done => { + it('should resolve with true if the membership is active', async () => { githubApi.get.and.resolveTo({state: 'active'}); - teams.isMemberById('user', [1]).then(isMember => { - expect(isMember).toBe(true); - done(); - }); + await expectAsync(teams.isMemberById('user', [1])).toBeResolvedTo(true); }); - it('should sequentially call \'get()\' until an active membership is found', done => { - const trainedResponses: {[pathname: string]: Promise} = { - '/teams/1/memberships/user': Promise.resolve({state: 'pending'}), - '/teams/2/memberships/user': Promise.reject(null), - '/teams/3/memberships/user': Promise.resolve({state: 'active'}), - }; - githubApi.get.and.callFake((pathname: string) => trainedResponses[pathname]); + it('should sequentially call \'get()\' until an active membership is found', async () => { + githubApi.get. + withArgs('/teams/1/memberships/user').and.resolveTo({state: 'pending'}). + withArgs('/teams/2/memberships/user').and.rejectWith(null). + withArgs('/teams/3/memberships/user').and.resolveTo({state: 'active'}); - teams.isMemberById('user', [1, 2, 3, 4]).then(isMember => { - expect(isMember).toBe(true); + await expectAsync(teams.isMemberById('user', [1, 2, 3, 4])).toBeResolvedTo(true); - expect(githubApi.get).toHaveBeenCalledTimes(3); - expect(githubApi.get.calls.argsFor(0)[0]).toBe('/teams/1/memberships/user'); - expect(githubApi.get.calls.argsFor(1)[0]).toBe('/teams/2/memberships/user'); - expect(githubApi.get.calls.argsFor(2)[0]).toBe('/teams/3/memberships/user'); - - done(); - }); + expect(githubApi.get).toHaveBeenCalledTimes(3); + expect(githubApi.get.calls.argsFor(0)[0]).toBe('/teams/1/memberships/user'); + expect(githubApi.get.calls.argsFor(1)[0]).toBe('/teams/2/memberships/user'); + expect(githubApi.get.calls.argsFor(2)[0]).toBe('/teams/3/memberships/user'); }); - it('should resolve with false if no active membership is found', done => { - const trainedResponses: {[pathname: string]: Promise} = { - '/teams/1/memberships/user': Promise.resolve({state: 'pending'}), - '/teams/2/memberships/user': Promise.reject(null), - '/teams/3/memberships/user': Promise.resolve({state: 'not active'}), - '/teams/4/memberships/user': Promise.reject(null), - }; - githubApi.get.and.callFake((pathname: string) => trainedResponses[pathname]); + it('should resolve with false if no active membership is found', async () => { + githubApi.get. + withArgs('/teams/1/memberships/user').and.resolveTo({state: 'pending'}). + withArgs('/teams/2/memberships/user').and.rejectWith(null). + withArgs('/teams/3/memberships/user').and.resolveTo({state: 'not active'}). + withArgs('/teams/4/memberships/user').and.rejectWith(null); - teams.isMemberById('user', [1, 2, 3, 4]).then(isMember => { - expect(isMember).toBe(false); + await expectAsync(teams.isMemberById('user', [1, 2, 3, 4])).toBeResolvedTo(false); - expect(githubApi.get).toHaveBeenCalledTimes(4); - expect(githubApi.get.calls.argsFor(0)[0]).toBe('/teams/1/memberships/user'); - expect(githubApi.get.calls.argsFor(1)[0]).toBe('/teams/2/memberships/user'); - expect(githubApi.get.calls.argsFor(2)[0]).toBe('/teams/3/memberships/user'); - expect(githubApi.get.calls.argsFor(3)[0]).toBe('/teams/4/memberships/user'); - - done(); - }); + expect(githubApi.get).toHaveBeenCalledTimes(4); + expect(githubApi.get.calls.argsFor(0)[0]).toBe('/teams/1/memberships/user'); + expect(githubApi.get.calls.argsFor(1)[0]).toBe('/teams/2/memberships/user'); + expect(githubApi.get.calls.argsFor(2)[0]).toBe('/teams/3/memberships/user'); + expect(githubApi.get.calls.argsFor(3)[0]).toBe('/teams/4/memberships/user'); }); }); @@ -162,14 +140,13 @@ describe('GithubTeams', () => { beforeEach(() => { teams = new GithubTeams(githubApi, 'foo'); - const mockResponse = Promise.resolve([{id: 1, slug: 'team1'}, {id: 2, slug: 'team2'}]); - teamsFetchAllSpy = spyOn(teams, 'fetchAll').and.returnValue(mockResponse); + teamsFetchAllSpy = spyOn(teams, 'fetchAll').and.resolveTo([{id: 1, slug: 'team1'}, {id: 2, slug: 'team2'}]); teamsIsMemberByIdSpy = spyOn(teams, 'isMemberById'); }); it('should return a promise', () => { - expect(teams.isMemberBySlug('user', ['team-slug'])).toEqual(jasmine.any(Promise)); + expect(teams.isMemberBySlug('user', ['team-slug'])).toBeInstanceOf(Promise); }); @@ -179,55 +156,46 @@ describe('GithubTeams', () => { }); - it('should resolve with false if \'fetchAll()\' rejects', done => { - teamsFetchAllSpy.and.callFake(() => Promise.reject(null)); - teams.isMemberBySlug('user', ['team-slug']).then(isMember => { - expect(isMember).toBe(false); - done(); - }); + it('should resolve with false if \'fetchAll()\' rejects', async () => { + teamsFetchAllSpy.and.rejectWith(null); + await expectAsync(teams.isMemberBySlug('user', ['team-slug'])).toBeResolvedTo(false); }); - it('should call \'isMemberById()\' with the correct params if no team is found', done => { - teams.isMemberBySlug('user', ['no-match']).then(() => { - expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('user', []); - done(); - }); + it('should call \'isMemberById()\' with the correct params if no team is found', async () => { + await teams.isMemberBySlug('user', ['no-match']); + expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('user', []); }); - it('should call \'isMemberById()\' with the correct params if teams are found', done => { - const spy = teamsIsMemberByIdSpy; + it('should call \'isMemberById()\' with the correct params if teams are found', async () => { + await teams.isMemberBySlug('userA', ['team1']); + expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('userA', [1]); - Promise.all([ - teams.isMemberBySlug('user', ['team1']).then(() => expect(spy).toHaveBeenCalledWith('user', [1])), - teams.isMemberBySlug('user', ['team2']).then(() => expect(spy).toHaveBeenCalledWith('user', [2])), - teams.isMemberBySlug('user', ['team1', 'team2']).then(() => expect(spy).toHaveBeenCalledWith('user', [1, 2])), - ]).then(done); + await teams.isMemberBySlug('userB', ['team2']); + expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('userB', [2]); + + await teams.isMemberBySlug('userC', ['team1', 'team2']); + expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('userC', [1, 2]); }); - it('should resolve with false if \'isMemberById()\' rejects', done => { - teamsIsMemberByIdSpy.and.callFake(() => Promise.reject(null)); - teams.isMemberBySlug('user', ['team1']).then(isMember => { - expect(isMember).toBe(false); - expect(teamsIsMemberByIdSpy).toHaveBeenCalled(); - done(); - }); + it('should resolve with false if \'isMemberById()\' rejects', async () => { + teamsIsMemberByIdSpy.and.rejectWith(null); + + await expectAsync(teams.isMemberBySlug('user', ['team1'])).toBeResolvedTo(false); + expect(teamsIsMemberByIdSpy).toHaveBeenCalled(); }); it('should resolve with the value \'isMemberById()\' resolves with', async () => { + teamsIsMemberByIdSpy.and.resolveTo(true); + await expectAsync(teams.isMemberBySlug('userA', ['team1'])).toBeResolvedTo(true); + expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('userA', [1]); - teamsIsMemberByIdSpy.and.callFake(() => Promise.resolve(true)); - const isMember1 = await teams.isMemberBySlug('user', ['team1']); - expect(isMember1).toBe(true); - expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('user', [1]); - - teamsIsMemberByIdSpy.and.callFake(() => Promise.resolve(false)); - const isMember2 = await teams.isMemberBySlug('user', ['team1']); - expect(isMember2).toBe(false); - expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('user', [1]); + teamsIsMemberByIdSpy.and.resolveTo(false); + await expectAsync(teams.isMemberBySlug('userB', ['team1'])).toBeResolvedTo(false); + expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('userB', [1]); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-creator.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-creator.spec.ts index 9d8fc53808..1c1e0a8ab9 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-creator.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-creator.spec.ts @@ -9,7 +9,8 @@ import {Logger} from '../../lib/common/utils'; import {BuildCreator} from '../../lib/preview-server/build-creator'; import {ChangedPrVisibilityEvent, CreatedBuildEvent} from '../../lib/preview-server/build-events'; import {PreviewServerError} from '../../lib/preview-server/preview-error'; -import {expectToBePreviewServerError} from './helpers'; +import {customAsyncMatchers} from './jasmine-custom-async-matchers'; + // Tests describe('BuildCreator', () => { @@ -24,6 +25,7 @@ describe('BuildCreator', () => { const publicShaDir = path.join(publicPrDir, shortSha); let bc: BuildCreator; + beforeEach(() => jasmine.addAsyncMatchers(customAsyncMatchers)); beforeEach(() => bc = new BuildCreator(buildsDir)); @@ -35,8 +37,8 @@ describe('BuildCreator', () => { it('should extend EventEmitter', () => { - expect(bc).toEqual(jasmine.any(BuildCreator)); - expect(bc).toEqual(jasmine.any(EventEmitter)); + expect(bc).toBeInstanceOf(BuildCreator); + expect(bc).toBeInstanceOf(EventEmitter); expect(Object.getPrototypeOf(bc)).toBe(BuildCreator.prototype); }); @@ -67,47 +69,43 @@ describe('BuildCreator', () => { const shaDir = isPublic ? publicShaDir : hiddenShaDir; - it('should return a promise', done => { + it('should return a promise', async () => { const promise = bc.create(pr, sha, archive, isPublic); - promise.then(done); // Do not complete the test (and release the spies) synchronously - // to avoid running the actual `extractArchive()`. + expect(promise).toBeInstanceOf(Promise); - expect(promise).toEqual(jasmine.any(Promise)); + // Do not complete the test (and release the spies) synchronously to avoid running the actual + // `extractArchive()`. + await promise; }); - it('should update the PR\'s visibility first if necessary', done => { - bcUpdatePrVisibilitySpy.and.callFake(() => expect(shellMkdirSpy).not.toHaveBeenCalled()); + it('should update the PR\'s visibility first if necessary', async () => { + await bc.create(pr, sha, archive, isPublic); - bc.create(pr, sha, archive, isPublic). - then(() => { - expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith(pr, isPublic); - expect(shellMkdirSpy).toHaveBeenCalled(); - }). - then(done); + expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledBefore(shellMkdirSpy); + expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith(pr, isPublic); + expect(shellMkdirSpy).toHaveBeenCalled(); }); - it('should create the build directory (and any parent directories)', done => { - bc.create(pr, sha, archive, isPublic). - then(() => expect(shellMkdirSpy).toHaveBeenCalledWith('-p', shaDir)). - then(done); + it('should create the build directory (and any parent directories)', async () => { + await bc.create(pr, sha, archive, isPublic); + expect(shellMkdirSpy).toHaveBeenCalledWith('-p', shaDir); }); - it('should extract the archive contents into the build directory', done => { - bc.create(pr, sha, archive, isPublic). - then(() => expect(bcExtractArchiveSpy).toHaveBeenCalledWith(archive, shaDir)). - then(done); + it('should extract the archive contents into the build directory', async () => { + await bc.create(pr, sha, archive, isPublic); + expect(bcExtractArchiveSpy).toHaveBeenCalledWith(archive, shaDir); }); - it('should emit a CreatedBuildEvent on success', done => { + it('should emit a CreatedBuildEvent on success', async () => { let emitted = false; bcEmitSpy.and.callFake((type: string, evt: CreatedBuildEvent) => { expect(type).toBe(CreatedBuildEvent.type); - expect(evt).toEqual(jasmine.any(CreatedBuildEvent)); + expect(evt).toBeInstanceOf(CreatedBuildEvent); expect(evt.pr).toBe(+pr); expect(evt.sha).toBe(shortSha); expect(evt.isPublic).toBe(isPublic); @@ -115,130 +113,108 @@ describe('BuildCreator', () => { emitted = true; }); - bc.create(pr, sha, archive, isPublic). - then(() => expect(emitted).toBe(true)). - then(done); + await bc.create(pr, sha, archive, isPublic); + expect(emitted).toBe(true); }); describe('on error', () => { - let existsValues: {[dir: string]: boolean}; - beforeEach(() => { - existsValues = { - [prDir]: false, - [shaDir]: false, - }; - - bcExistsSpy.and.callFake((dir: string) => existsValues[dir]); + bcExistsSpy.and.returnValue(false); }); - it('should abort and skip further operations if changing the PR\'s visibility fails', done => { + it('should abort and skip further operations if changing the PR\'s visibility fails', async () => { const mockError = new PreviewServerError(543, 'Test'); - bcUpdatePrVisibilitySpy.and.callFake(() => Promise.reject(mockError)); + bcUpdatePrVisibilitySpy.and.rejectWith(mockError); - bc.create(pr, sha, archive, isPublic).catch(err => { - expect(err).toBe(mockError); + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejectedWith(mockError); - expect(bcExistsSpy).not.toHaveBeenCalled(); - expect(shellMkdirSpy).not.toHaveBeenCalled(); - expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - - done(); - }); + expect(bcExistsSpy).not.toHaveBeenCalled(); + expect(shellMkdirSpy).not.toHaveBeenCalled(); + expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should abort and skip further operations if the build does already exist', done => { - existsValues[shaDir] = true; - bc.create(pr, sha, archive, isPublic).catch(err => { - const publicOrNot = isPublic ? 'public' : 'non-public'; - expectToBePreviewServerError(err, 409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`); - expect(shellMkdirSpy).not.toHaveBeenCalled(); - expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - done(); - }); + it('should abort and skip further operations if the build does already exist', async () => { + bcExistsSpy.withArgs(shaDir).and.returnValue(true); + + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejectedWithPreviewServerError( + 409, `Request to overwrite existing ${isPublic ? '' : 'non-'}public directory: ${shaDir}`); + + expect(shellMkdirSpy).not.toHaveBeenCalled(); + expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should detect existing build directory after visibility change', done => { - bcUpdatePrVisibilitySpy.and.callFake(() => existsValues[prDir] = existsValues[shaDir] = true); + it('should detect existing build directory after visibility change', async () => { + bcUpdatePrVisibilitySpy.and.callFake(() => bcExistsSpy.and.returnValue(true)); expect(bcExistsSpy(prDir)).toBe(false); expect(bcExistsSpy(shaDir)).toBe(false); - bc.create(pr, sha, archive, isPublic).catch(err => { - const publicOrNot = isPublic ? 'public' : 'non-public'; - expectToBePreviewServerError(err, 409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`); - expect(shellMkdirSpy).not.toHaveBeenCalled(); - expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - done(); - }); + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejectedWithPreviewServerError( + 409, `Request to overwrite existing ${isPublic ? '' : 'non-'}public directory: ${shaDir}`); + + expect(shellMkdirSpy).not.toHaveBeenCalled(); + expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should abort and skip further operations if it fails to create the directories', done => { + it('should abort and skip further operations if it fails to create the directories', async () => { shellMkdirSpy.and.throwError(''); - bc.create(pr, sha, archive, isPublic).catch(() => { - expect(shellMkdirSpy).toHaveBeenCalled(); - expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - done(); - }); + + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejected(); + + expect(shellMkdirSpy).toHaveBeenCalled(); + expect(bcExtractArchiveSpy).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should abort and skip further operations if it fails to extract the archive', done => { - bcExtractArchiveSpy.and.throwError(''); - bc.create(pr, sha, archive, isPublic).catch(() => { - expect(shellMkdirSpy).toHaveBeenCalled(); - expect(bcExtractArchiveSpy).toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - done(); - }); - }); - - - it('should delete the PR directory (for new PR)', done => { - bcExtractArchiveSpy.and.throwError(''); - bc.create(pr, sha, archive, isPublic).catch(() => { - expect(shellRmSpy).toHaveBeenCalledWith('-rf', prDir); - done(); - }); - }); - - - it('should delete the SHA directory (for existing PR)', done => { - existsValues[prDir] = true; + it('should abort and skip further operations if it fails to extract the archive', async () => { bcExtractArchiveSpy.and.throwError(''); - bc.create(pr, sha, archive, isPublic).catch(() => { - expect(shellRmSpy).toHaveBeenCalledWith('-rf', shaDir); - done(); - }); + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejected(); + + expect(shellMkdirSpy).toHaveBeenCalled(); + expect(bcExtractArchiveSpy).toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should reject with an PreviewServerError', done => { + it('should delete the PR directory (for new PR)', async () => { + bcExtractArchiveSpy.and.throwError(''); + + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejected(); + expect(shellRmSpy).toHaveBeenCalledWith('-rf', prDir); + }); + + + it('should delete the SHA directory (for existing PR)', async () => { + bcExistsSpy.withArgs(prDir).and.returnValue(true); + bcExtractArchiveSpy.and.throwError(''); + + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejected(); + expect(shellRmSpy).toHaveBeenCalledWith('-rf', shaDir); + }); + + + it('should reject with an PreviewServerError', async () => { // tslint:disable-next-line: no-string-throw shellMkdirSpy.and.callFake(() => { throw 'Test'; }); - bc.create(pr, sha, archive, isPublic).catch(err => { - expectToBePreviewServerError(err, 500, `Error while creating preview at: ${shaDir}\nTest`); - done(); - }); + + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejectedWithPreviewServerError( + 500, `Error while creating preview at: ${shaDir}\nTest`); }); - it('should pass PreviewServerError instances unmodified', done => { + it('should pass PreviewServerError instances unmodified', async () => { shellMkdirSpy.and.callFake(() => { throw new PreviewServerError(543, 'Test'); }); - bc.create(pr, sha, archive, isPublic).catch(err => { - expectToBePreviewServerError(err, 543, 'Test'); - done(); - }); + await expectAsync(bc.create(pr, sha, archive, isPublic)).toBeRejectedWithPreviewServerError(543, 'Test'); }); }); @@ -265,12 +241,12 @@ describe('BuildCreator', () => { }); - it('should return a promise', done => { + it('should return a promise', async () => { const promise = bc.updatePrVisibility(pr, true); - promise.then(done); // Do not complete the test (and release the spies) synchronously - // to avoid running the actual `extractArchive()`. + expect(promise).toBeInstanceOf(Promise); - expect(promise).toEqual(jasmine.any(Promise)); + // Do not complete the test (and release the spies) synchronously to avoid running the actual `extractArchive()`. + await promise; }); @@ -279,58 +255,53 @@ describe('BuildCreator', () => { const newPrDir = makePublic ? publicPrDir : hiddenPrDir; - it('should rename the directory', done => { - bc.updatePrVisibility(pr, makePublic). - then(() => expect(shellMvSpy).toHaveBeenCalledWith(oldPrDir, newPrDir)). - then(done); + it('should rename the directory', async () => { + await bc.updatePrVisibility(pr, makePublic); + expect(shellMvSpy).toHaveBeenCalledWith(oldPrDir, newPrDir); }); describe('when the visibility is updated', () => { - it('should resolve to true', done => { - bc.updatePrVisibility(pr, makePublic). - then(result => expect(result).toBe(true)). - then(done); + it('should resolve to true', async () => { + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeResolvedTo(true); }); - it('should rename the directory', done => { - bc.updatePrVisibility(pr, makePublic). - then(() => expect(shellMvSpy).toHaveBeenCalledWith(oldPrDir, newPrDir)). - then(done); + it('should rename the directory', async () => { + await bc.updatePrVisibility(pr, makePublic); + expect(shellMvSpy).toHaveBeenCalledWith(oldPrDir, newPrDir); }); - it('should emit a ChangedPrVisibilityEvent on success', done => { + it('should emit a ChangedPrVisibilityEvent on success', async () => { let emitted = false; bcEmitSpy.and.callFake((type: string, evt: ChangedPrVisibilityEvent) => { expect(type).toBe(ChangedPrVisibilityEvent.type); - expect(evt).toEqual(jasmine.any(ChangedPrVisibilityEvent)); + expect(evt).toBeInstanceOf(ChangedPrVisibilityEvent); expect(evt.pr).toBe(+pr); - expect(evt.shas).toEqual(jasmine.any(Array)); + expect(evt.shas).toBeInstanceOf(Array); expect(evt.isPublic).toBe(makePublic); emitted = true; }); - bc.updatePrVisibility(pr, makePublic). - then(() => expect(emitted).toBe(true)). - then(done); + await bc.updatePrVisibility(pr, makePublic); + expect(emitted).toBe(true); }); - it('should include all shas in the emitted event', done => { + it('should include all shas in the emitted event', async () => { const shas = ['foo', 'bar', 'baz']; let emitted = false; - bcListShasByDate.and.callFake(() => Promise.resolve(shas)); + bcListShasByDate.and.resolveTo(shas); bcEmitSpy.and.callFake((type: string, evt: ChangedPrVisibilityEvent) => { expect(bcListShasByDate).toHaveBeenCalledWith(newPrDir); expect(type).toBe(ChangedPrVisibilityEvent.type); - expect(evt).toEqual(jasmine.any(ChangedPrVisibilityEvent)); + expect(evt).toBeInstanceOf(ChangedPrVisibilityEvent); expect(evt.pr).toBe(+pr); expect(evt.shas).toBe(shas); expect(evt.isPublic).toBe(makePublic); @@ -338,94 +309,82 @@ describe('BuildCreator', () => { emitted = true; }); - bc.updatePrVisibility(pr, makePublic). - then(() => expect(emitted).toBe(true)). - then(done); + await bc.updatePrVisibility(pr, makePublic); + expect(emitted).toBe(true); }); }); - it('should do nothing if the visibility is already up-to-date', done => { + it('should do nothing if the visibility is already up-to-date', async () => { bcExistsSpy.and.callFake((dir: string) => dir === newPrDir); - bc.updatePrVisibility(pr, makePublic). - then(result => { - expect(result).toBe(false); - expect(shellMvSpy).not.toHaveBeenCalled(); - expect(bcListShasByDate).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - }). - then(done); + + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeResolvedTo(false); + + expect(shellMvSpy).not.toHaveBeenCalled(); + expect(bcListShasByDate).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should do nothing if the PR directory does not exist', done => { + it('should do nothing if the PR directory does not exist', async () => { bcExistsSpy.and.returnValue(false); - bc.updatePrVisibility(pr, makePublic). - then(result => { - expect(result).toBe(false); - expect(shellMvSpy).not.toHaveBeenCalled(); - expect(bcListShasByDate).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - }). - then(done); + + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeResolvedTo(false); + + expect(shellMvSpy).not.toHaveBeenCalled(); + expect(bcListShasByDate).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); describe('on error', () => { - it('should abort and skip further operations if both directories exist', done => { + it('should abort and skip further operations if both directories exist', async () => { bcExistsSpy.and.returnValue(true); - bc.updatePrVisibility(pr, makePublic).catch(err => { - expectToBePreviewServerError(err, 409, - `Request to move '${oldPrDir}' to existing directory '${newPrDir}'.`); - expect(shellMvSpy).not.toHaveBeenCalled(); - expect(bcListShasByDate).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - done(); - }); + + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeRejectedWithPreviewServerError( + 409, `Request to move '${oldPrDir}' to existing directory '${newPrDir}'.`); + + expect(shellMvSpy).not.toHaveBeenCalled(); + expect(bcListShasByDate).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should abort and skip further operations if it fails to rename the directory', done => { + it('should abort and skip further operations if it fails to rename the directory', async () => { shellMvSpy.and.throwError(''); - bc.updatePrVisibility(pr, makePublic).catch(() => { - expect(shellMvSpy).toHaveBeenCalled(); - expect(bcListShasByDate).not.toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - done(); - }); + + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeRejected(); + + expect(shellMvSpy).toHaveBeenCalled(); + expect(bcListShasByDate).not.toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should abort and skip further operations if it fails to list the SHAs', done => { + it('should abort and skip further operations if it fails to list the SHAs', async () => { bcListShasByDate.and.throwError(''); - bc.updatePrVisibility(pr, makePublic).catch(() => { - expect(shellMvSpy).toHaveBeenCalled(); - expect(bcListShasByDate).toHaveBeenCalled(); - expect(bcEmitSpy).not.toHaveBeenCalled(); - done(); - }); + + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeRejected(); + + expect(shellMvSpy).toHaveBeenCalled(); + expect(bcListShasByDate).toHaveBeenCalled(); + expect(bcEmitSpy).not.toHaveBeenCalled(); }); - it('should reject with an PreviewServerError', done => { + it('should reject with an PreviewServerError', async () => { // tslint:disable-next-line: no-string-throw shellMvSpy.and.callFake(() => { throw 'Test'; }); - bc.updatePrVisibility(pr, makePublic).catch(err => { - expectToBePreviewServerError(err, 500, - `Error while making PR ${pr} ${makePublic ? 'public' : 'hidden'}.\nTest`); - done(); - }); + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeRejectedWithPreviewServerError( + 500, `Error while making PR ${pr} ${makePublic ? 'public' : 'hidden'}.\nTest`); }); - it('should pass PreviewServerError instances unmodified', done => { + it('should pass PreviewServerError instances unmodified', async () => { shellMvSpy.and.callFake(() => { throw new PreviewServerError(543, 'Test'); }); - bc.updatePrVisibility(pr, makePublic).catch(err => { - expectToBePreviewServerError(err, 543, 'Test'); - done(); - }); + await expectAsync(bc.updatePrVisibility(pr, makePublic)).toBeRejectedWithPreviewServerError(543, 'Test'); }); }); @@ -450,7 +409,7 @@ describe('BuildCreator', () => { it('should return a promise', () => { - expect((bc as any).exists('foo')).toEqual(jasmine.any(Promise)); + expect((bc as any).exists('foo')).toBeInstanceOf(Promise); }); @@ -460,25 +419,29 @@ describe('BuildCreator', () => { }); - it('should resolve with \'true\' if \'fs.access()\' succeeds', done => { - Promise. - all([(bc as any).exists('foo'), (bc as any).exists('bar')]). - then(results => expect(results).toEqual([true, true])). - then(done); + it('should resolve with \'true\' if \'fs.access()\' succeeds', async () => { + const existsPromises = [ + (bc as any).exists('foo'), + (bc as any).exists('bar'), + ]; fsAccessCbs[0](); fsAccessCbs[1](null); + + await expectAsync(Promise.all(existsPromises)).toBeResolvedTo([true, true]); }); - it('should resolve with \'false\' if \'fs.access()\' errors', done => { - Promise. - all([(bc as any).exists('foo'), (bc as any).exists('bar')]). - then(results => expect(results).toEqual([false, false])). - then(done); + it('should resolve with \'false\' if \'fs.access()\' errors', async () => { + const existsPromises = [ + (bc as any).exists('foo'), + (bc as any).exists('bar'), + ]; fsAccessCbs[0]('Error'); fsAccessCbs[1](new Error()); + + await expectAsync(Promise.all(existsPromises)).toBeResolvedTo([false, false]); }); }); @@ -505,7 +468,7 @@ describe('BuildCreator', () => { it('should return a promise', () => { - expect((bc as any).extractArchive('foo', 'bar')).toEqual(jasmine.any(Promise)); + expect((bc as any).extractArchive('foo', 'bar')).toBeInstanceOf(Promise); }); @@ -517,78 +480,68 @@ describe('BuildCreator', () => { }); - it('should log (as a warning) any stderr output if extracting succeeded', done => { - (bc as any).extractArchive('foo', 'bar'). - then(() => expect(consoleWarnSpy).toHaveBeenCalledWith('This is stderr')). - then(done); - + it('should log (as a warning) any stderr output if extracting succeeded', async () => { + const extractPromise = (bc as any).extractArchive('foo', 'bar'); cpExecCbs[0](null, 'This is stdout', 'This is stderr'); + + await expectAsync(extractPromise).toBeResolved(); + expect(consoleWarnSpy).toHaveBeenCalledWith('This is stderr'); }); - it('should make the build directory non-writable', done => { - (bc as any).extractArchive('foo', 'bar'). - then(() => expect(shellChmodSpy).toHaveBeenCalledWith('-R', 'a-w', 'bar')). - then(done); - + it('should make the build directory non-writable', async () => { + const extractPromise = (bc as any).extractArchive('foo', 'bar'); cpExecCbs[0](); + + await expectAsync(extractPromise).toBeResolved(); + expect(shellChmodSpy).toHaveBeenCalledWith('-R', 'a-w', 'bar'); }); - it('should delete the build artifact file on success', done => { - (bc as any).extractArchive('input/file', 'output/dir'). - then(() => expect(shellRmSpy).toHaveBeenCalledWith('-f', 'input/file')). - then(done); - + it('should delete the build artifact file on success', async () => { + const extractPromise = (bc as any).extractArchive('input/file', 'output/dir'); cpExecCbs[0](); + + await expectAsync(extractPromise).toBeResolved(); + expect(shellRmSpy).toHaveBeenCalledWith('-f', 'input/file'); }); describe('on error', () => { - it('should abort and skip further operations if it fails to extract the archive', done => { - (bc as any).extractArchive('foo', 'bar').catch((err: any) => { - expect(shellChmodSpy).not.toHaveBeenCalled(); - expect(shellRmSpy).not.toHaveBeenCalled(); - expect(err).toBe('Test'); - done(); - }); - + it('should abort and skip further operations if it fails to extract the archive', async () => { + const extractPromise = (bc as any).extractArchive('foo', 'bar'); cpExecCbs[0]('Test'); + + await expectAsync(extractPromise).toBeRejectedWith('Test'); + expect(shellChmodSpy).not.toHaveBeenCalled(); + expect(shellRmSpy).not.toHaveBeenCalled(); }); - it('should abort and skip further operations if it fails to make non-writable', done => { - (bc as any).extractArchive('foo', 'bar').catch((err: any) => { - expect(shellChmodSpy).toHaveBeenCalled(); - expect(shellRmSpy).not.toHaveBeenCalled(); - expect(err).toBe('Test'); - done(); - }); - - shellChmodSpy.and.callFake(() => { - // tslint:disable-next-line: no-string-throw - throw 'Test'; - }); + it('should abort and skip further operations if it fails to make non-writable', async () => { + // tslint:disable-next-line: no-string-throw + shellChmodSpy.and.callFake(() => { throw 'Test'; }); + const extractPromise = (bc as any).extractArchive('foo', 'bar'); cpExecCbs[0](); + + await expectAsync(extractPromise).toBeRejectedWith('Test'); + expect(shellChmodSpy).toHaveBeenCalled(); + expect(shellRmSpy).not.toHaveBeenCalled(); }); - it('should abort and reject if it fails to remove the build artifact file', done => { - (bc as any).extractArchive('foo', 'bar').catch((err: any) => { - expect(shellChmodSpy).toHaveBeenCalled(); - expect(shellRmSpy).toHaveBeenCalled(); - expect(err).toBe('Test'); - done(); - }); - - shellRmSpy.and.callFake(() => { - // tslint:disable-next-line: no-string-throw - throw 'Test'; - }); + it('should abort and reject if it fails to remove the build artifact file', async () => { + // tslint:disable-next-line: no-string-throw + shellRmSpy.and.callFake(() => { throw 'Test'; }); + const extractPromise = (bc as any).extractArchive('foo', 'bar'); cpExecCbs[0](); + + await expectAsync(extractPromise).toBeRejectedWith('Test'); + expect(shellChmodSpy).toHaveBeenCalled(); + expect(shellRmSpy).toHaveBeenCalled(); }); }); @@ -609,58 +562,50 @@ describe('BuildCreator', () => { }); - it('should return a promise', done => { + it('should return a promise', async () => { const promise = (bc as any).listShasByDate('input/dir'); - promise.then(done); // Do not complete the test (and release the spies) synchronously - // to avoid running the actual `ls()`. + expect(promise).toBeInstanceOf(Promise); - expect(promise).toEqual(jasmine.any(Promise)); + // Do not complete the test (and release the spies) synchronously to avoid running the actual `ls()`. + await promise; }); - it('should `ls()` files with their metadata', done => { - (bc as any).listShasByDate('input/dir'). - then(() => expect(shellLsSpy).toHaveBeenCalledWith('-l', 'input/dir')). - then(done); + it('should `ls()` files with their metadata', async () => { + await (bc as any).listShasByDate('input/dir'); + expect(shellLsSpy).toHaveBeenCalledWith('-l', 'input/dir'); }); - it('should reject if listing files fails', done => { - shellLsSpy.and.callFake(() => Promise.reject('Test')); - (bc as any).listShasByDate('input/dir').catch((err: string) => { - expect(err).toBe('Test'); - done(); - }); + it('should reject if listing files fails', async () => { + shellLsSpy.and.rejectWith('Test'); + await expectAsync((bc as any).listShasByDate('input/dir')).toBeRejectedWith('Test'); }); - it('should return the filenames', done => { - shellLsSpy.and.callFake(() => Promise.resolve([ + it('should return the filenames', async () => { + shellLsSpy.and.resolveTo([ lsResult('foo', 100), lsResult('bar', 200), lsResult('baz', 300), - ])); + ]); - (bc as any).listShasByDate('input/dir'). - then((shas: string[]) => expect(shas).toEqual(['foo', 'bar', 'baz'])). - then(done); + await expectAsync((bc as any).listShasByDate('input/dir')).toBeResolvedTo(['foo', 'bar', 'baz']); }); - it('should sort by date', done => { - shellLsSpy.and.callFake(() => Promise.resolve([ + it('should sort by date', async () => { + shellLsSpy.and.resolveTo([ lsResult('foo', 300), lsResult('bar', 100), lsResult('baz', 200), - ])); + ]); - (bc as any).listShasByDate('input/dir'). - then((shas: string[]) => expect(shas).toEqual(['bar', 'baz', 'foo'])). - then(done); + await expectAsync((bc as any).listShasByDate('input/dir')).toBeResolvedTo(['bar', 'baz', 'foo']); }); - it('should not break with ShellJS\' custom `sort()` method', done => { + it('should not break with ShellJS\' custom `sort()` method', async () => { const mockArray = [ lsResult('foo', 300), lsResult('bar', 100), @@ -668,26 +613,21 @@ describe('BuildCreator', () => { ]; mockArray.sort = jasmine.createSpy('sort'); - shellLsSpy.and.callFake(() => Promise.resolve(mockArray)); - (bc as any).listShasByDate('input/dir'). - then((shas: string[]) => { - expect(shas).toEqual(['bar', 'baz', 'foo']); - expect(mockArray.sort).not.toHaveBeenCalled(); - }). - then(done); + shellLsSpy.and.resolveTo(mockArray); + + await expectAsync((bc as any).listShasByDate('input/dir')).toBeResolvedTo(['bar', 'baz', 'foo']); + expect(mockArray.sort).not.toHaveBeenCalled(); }); - it('should only include directories', done => { - shellLsSpy.and.callFake(() => Promise.resolve([ + it('should only include directories', async () => { + shellLsSpy.and.resolveTo([ lsResult('foo', 100), lsResult('bar', 200, false), lsResult('baz', 300), - ])); + ]); - (bc as any).listShasByDate('input/dir'). - then((shas: string[]) => expect(shas).toEqual(['foo', 'baz'])). - then(done); + await expectAsync((bc as any).listShasByDate('input/dir')).toBeResolvedTo(['foo', 'baz']); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-retriever.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-retriever.spec.ts index 8f174fddca..bd7a65a50d 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-retriever.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-retriever.spec.ts @@ -32,9 +32,8 @@ describe('BuildRetriever', () => { }; api = new CircleCiApi('ORG', 'REPO', 'TOKEN'); - spyOn(api, 'getBuildInfo').and.callFake(() => Promise.resolve(BUILD_INFO)); - getBuildArtifactUrlSpy = spyOn(api, 'getBuildArtifactUrl') - .and.callFake(() => Promise.resolve(BASE_URL + ARTIFACT_PATH)); + spyOn(api, 'getBuildInfo').and.resolveTo(BUILD_INFO); + getBuildArtifactUrlSpy = spyOn(api, 'getBuildArtifactUrl').and.resolveTo(BASE_URL + ARTIFACT_PATH); WRITEFILE_RESULT = undefined; writeFileSpy = spyOn(fs, 'writeFile').and.callFake( @@ -57,6 +56,7 @@ describe('BuildRetriever', () => { expect(() => new BuildRetriever(api, -1, DOWNLOAD_DIR)) .toThrowError(`Invalid parameter "downloadSizeLimit" should be a number greater than 0.`); }); + it('should fail if the "downloadDir" is missing', () => { expect(() => new BuildRetriever(api, MAX_DOWNLOAD_SIZE, '')) .toThrowError(`Missing or empty required parameter 'downloadDir'!`); @@ -73,14 +73,10 @@ describe('BuildRetriever', () => { }); it('should error if it is not possible to extract the PR number from the branch', async () => { + BUILD_INFO.branch = 'master'; const retriever = new BuildRetriever(api, MAX_DOWNLOAD_SIZE, DOWNLOAD_DIR); - try { - BUILD_INFO.branch = 'master'; - await retriever.getGithubInfo(12345); - throw new Error('Exception Expected'); - } catch (error) { - expect(error.message).toEqual('No PR found in branch field: master'); - } + + await expectAsync(retriever.getGithubInfo(12345)).toBeRejectedWithError('No PR found in branch field: master'); }); }); @@ -111,12 +107,10 @@ describe('BuildRetriever', () => { it('should fail if the artifact is too large', async () => { const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(200, ARTIFACT_CONTENTS); retriever = new BuildRetriever(api, 10, DOWNLOAD_DIR); - try { - await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH); - throw new Error('Exception Expected'); - } catch (error) { - expect(error.status).toEqual(413); - } + + await expectAsync(retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH)). + toBeRejectedWith(jasmine.objectContaining({status: 413})); + artifactRequest.done(); }); @@ -144,50 +138,40 @@ describe('BuildRetriever', () => { artifactRequest.done(); }); - it('should fail if the CircleCI API fails', async () => { - try { - getBuildArtifactUrlSpy.and.callFake(() => Promise.reject('getBuildArtifactUrl failed')); - await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH); - throw new Error('Exception Expected'); - } catch (error) { - expect(error.message).toEqual('CircleCI artifact download failed (getBuildArtifactUrl failed)'); - } + it('should fail if the CircleCI API fails', async () => { + getBuildArtifactUrlSpy.and.rejectWith('getBuildArtifactUrl failed'); + await expectAsync(retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH)). + toBeRejectedWithError('CircleCI artifact download failed (getBuildArtifactUrl failed)'); }); - it('should fail if the URL fetch errors', async () => { + it('should fail if the URL fetch errors', async () => { // create a new handler that errors const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).replyWithError('Artifact Request Failed'); - try { - await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH); - throw new Error('Exception Expected'); - } catch (error) { - expect(error.message).toEqual('CircleCI artifact download failed ' + + + await expectAsync(retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH)).toBeRejectedWithError( + 'CircleCI artifact download failed ' + '(request to http://test.com/some/path/build.zip failed, reason: Artifact Request Failed)'); - } + artifactRequest.done(); }); - it('should fail if the URL fetch 404s', async () => { + it('should fail if the URL fetch 404s', async () => { // create a new handler that errors const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(404, 'No such artifact'); - try { - await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH); - throw new Error('Exception Expected'); - } catch (error) { - expect(error.message).toEqual('CircleCI artifact download failed (Error 404 - Not Found)'); - } + + await expectAsync(retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH)). + toBeRejectedWithError('CircleCI artifact download failed (Error 404 - Not Found)'); + artifactRequest.done(); }); - it('should fail if file write fails', async () => { + it('should fail if file write fails', async () => { const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(200, ARTIFACT_CONTENTS); - try { - WRITEFILE_RESULT = 'Test Error'; - await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH); - throw new Error('Exception Expected'); - } catch (error) { - expect(error.message).toEqual('CircleCI artifact download failed (Test Error)'); - } + WRITEFILE_RESULT = 'Test Error'; + + await expectAsync(retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH)). + toBeRejectedWithError('CircleCI artifact download failed (Test Error)'); + artifactRequest.done(); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-verifier.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-verifier.spec.ts index 1a28db0fdc..a977ecb99e 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-verifier.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/build-verifier.spec.ts @@ -51,10 +51,10 @@ describe('BuildVerifier', () => { describe('getSignificantFilesChanged', () => { it('should return false if none of the fetched files match the given pattern', async () => { const fetchFilesSpy = spyOn(prs, 'fetchFiles'); - fetchFilesSpy.and.callFake(() => Promise.resolve([ + fetchFilesSpy.and.resolveTo([ {filename: 'a/b/c', sha: 'a1'}, {filename: 'd/e/f', sha: 'b2'}, - ])); + ]); expect(await bv.getSignificantFilesChanged(777, /^x/)).toEqual(false); expect(fetchFilesSpy).toHaveBeenCalledWith(777); @@ -81,37 +81,30 @@ describe('BuildVerifier', () => { user: {login: 'username'}, }; - prsFetchSpy = spyOn(GithubPullRequests.prototype, 'fetch'). - and.callFake(() => Promise.resolve(mockPrInfo)); - - teamsIsMemberBySlugSpy = spyOn(GithubTeams.prototype, 'isMemberBySlug'). - and.callFake(() => Promise.resolve(true)); + prsFetchSpy = spyOn(GithubPullRequests.prototype, 'fetch').and.resolveTo(mockPrInfo); + teamsIsMemberBySlugSpy = spyOn(GithubTeams.prototype, 'isMemberBySlug').and.resolveTo(true); }); - it('should return a promise', done => { + it('should return a promise', async () => { const promise = bv.getPrIsTrusted(pr); - promise.then(done); // Do not complete the test (and release the spies) synchronously - // to avoid running the actual `GithubTeams#isMemberBySlug()`. + expect(promise).toBeInstanceOf(Promise); - expect(promise).toEqual(jasmine.any(Promise)); + // Do not complete the test (and release the spies) synchronously to avoid running the actual + // `GithubTeams#isMemberBySlug()`. + await promise; }); - it('should fetch the corresponding PR', done => { - bv.getPrIsTrusted(pr).then(() => { - expect(prsFetchSpy).toHaveBeenCalledWith(pr); - done(); - }); + it('should fetch the corresponding PR', async () => { + await bv.getPrIsTrusted(pr); + expect(prsFetchSpy).toHaveBeenCalledWith(pr); }); - it('should fail if fetching the PR errors', done => { - prsFetchSpy.and.callFake(() => Promise.reject('Test')); - bv.getPrIsTrusted(pr).catch(err => { - expect(err).toBe('Test'); - done(); - }); + it('should fail if fetching the PR errors', async () => { + prsFetchSpy.and.rejectWith('Test'); + await expectAsync(bv.getPrIsTrusted(pr)).toBeRejectedWith('Test'); }); @@ -120,19 +113,14 @@ describe('BuildVerifier', () => { beforeEach(() => mockPrInfo.labels.push({name: 'trusted: pr-label'})); - it('should resolve to true', done => { - bv.getPrIsTrusted(pr).then(isTrusted => { - expect(isTrusted).toBe(true); - done(); - }); + it('should resolve to true', async () => { + await expectAsync(bv.getPrIsTrusted(pr)).toBeResolvedTo(true); }); - it('should not try to verify the author\'s membership status', done => { - bv.getPrIsTrusted(pr).then(() => { - expect(teamsIsMemberBySlugSpy).not.toHaveBeenCalled(); - done(); - }); + it('should not try to verify the author\'s membership status', async () => { + await expectAsync(bv.getPrIsTrusted(pr)); + expect(teamsIsMemberBySlugSpy).not.toHaveBeenCalled(); }); }); @@ -140,40 +128,27 @@ describe('BuildVerifier', () => { describe('when the PR does not have the "trusted PR" label', () => { - it('should verify the PR author\'s membership in the specified teams', done => { - bv.getPrIsTrusted(pr).then(() => { - expect(teamsIsMemberBySlugSpy).toHaveBeenCalledWith('username', ['team1', 'team2']); - done(); - }); + it('should verify the PR author\'s membership in the specified teams', async () => { + await bv.getPrIsTrusted(pr); + expect(teamsIsMemberBySlugSpy).toHaveBeenCalledWith('username', ['team1', 'team2']); }); - it('should fail if verifying membership errors', done => { - teamsIsMemberBySlugSpy.and.callFake(() => Promise.reject('Test')); - bv.getPrIsTrusted(pr).catch(err => { - expect(err).toBe('Test'); - done(); - }); + it('should fail if verifying membership errors', async () => { + teamsIsMemberBySlugSpy.and.rejectWith('Test'); + await expectAsync(bv.getPrIsTrusted(pr)).toBeRejectedWith('Test'); }); - it('should resolve to true if the PR\'s author is a member', done => { - teamsIsMemberBySlugSpy.and.callFake(() => Promise.resolve(true)); - - bv.getPrIsTrusted(pr).then(isTrusted => { - expect(isTrusted).toBe(true); - done(); - }); + it('should resolve to true if the PR\'s author is a member', async () => { + teamsIsMemberBySlugSpy.and.resolveTo(true); + await expectAsync(bv.getPrIsTrusted(pr)).toBeResolvedTo(true); }); - it('should resolve to false if the PR\'s author is not a member', done => { - teamsIsMemberBySlugSpy.and.callFake(() => Promise.resolve(false)); - - bv.getPrIsTrusted(pr).then(isTrusted => { - expect(isTrusted).toBe(false); - done(); - }); + it('should resolve to false if the PR\'s author is not a member', async () => { + teamsIsMemberBySlugSpy.and.resolveTo(false); + await expectAsync(bv.getPrIsTrusted(pr)).toBeResolvedTo(false); }); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/helpers.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/helpers.ts deleted file mode 100644 index 190774dbfb..0000000000 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/helpers.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {PreviewServerError} from '../../lib/preview-server/preview-error'; - -export const expectToBePreviewServerError = (actual: PreviewServerError, status?: number, message?: string) => { - expect(actual).toEqual(jasmine.any(PreviewServerError)); - if (status != null) { - expect(actual.status).toBe(status); - } - if (message != null) { - expect(actual.message).toBe(message); - } -}; diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/jasmine-custom-async-matchers-types.d.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/jasmine-custom-async-matchers-types.d.ts new file mode 100644 index 0000000000..8ea1e7105d --- /dev/null +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/jasmine-custom-async-matchers-types.d.ts @@ -0,0 +1,5 @@ +declare module jasmine { + interface AsyncMatchers { + toBeRejectedWithPreviewServerError(status: number, message?: string | RegExp): Promise; + } +} diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/jasmine-custom-async-matchers.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/jasmine-custom-async-matchers.ts new file mode 100644 index 0000000000..b6180a8e10 --- /dev/null +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/jasmine-custom-async-matchers.ts @@ -0,0 +1,59 @@ +import {PreviewServerError} from '../../lib/preview-server/preview-error'; + + +// Matchers +const toBeRejectedWithPreviewServerError: jasmine.CustomAsyncMatcherFactory = () => { + return { + async compare(actualPromise: Promise, expectedStatus: number, expectedMessage?: string | RegExp) { + if (!(actualPromise instanceof Promise)) { + throw new Error(`Expected '${toBeRejectedWithPreviewServerError.name}()' to be called on a promise.`); + } + + try { + await actualPromise; + + return { + pass: false, + message: `Expected a promise to be rejected with a '${PreviewServerError.name}', but it was resolved.`, + }; + } catch (actualError) { + const actualPrintValue = stringify(actualError); + const expectedPrintValue = + stringify(new PreviewServerError(expectedStatus, expectedMessage && `${expectedMessage}`)); + + const pass = errorMatches(actualError, expectedStatus, expectedMessage); + const message = + `Expected a promise ${pass ? 'not ' : ''}to be rejected with ${expectedPrintValue}, but is was` + + `${pass ? '' : ` rejected with ${actualPrintValue}`}.`; + + return {pass, message}; + } + }, + }; + + // Helpers + function errorMatches(actualErr: unknown, expectedStatus: number, expectedMsg?: string | RegExp): boolean { + if (!(actualErr instanceof PreviewServerError)) return false; + if (actualErr.status !== expectedStatus) return false; + return messageMatches(actualErr.message, expectedMsg); + } + + function messageMatches(actualMsg: string, expectedMsg?: string | RegExp): boolean { + if (typeof expectedMsg === 'undefined') return true; + if (typeof expectedMsg === 'string') return actualMsg === expectedMsg; + return expectedMsg.test(actualMsg); + } + + function stringify(value: unknown): string { + if (value instanceof PreviewServerError) { + return `${PreviewServerError.name}(${value.status}${value.message ? `, ${value.message}` : ''})`; + } + + return jasmine.pp(value); + } +}; + +// Exports +export const customAsyncMatchers: jasmine.CustomAsyncMatcherFactories = { + toBeRejectedWithPreviewServerError, +}; diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-error.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-error.spec.ts index 11a1e0eabc..61ea1a0c9b 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-error.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-error.spec.ts @@ -9,8 +9,8 @@ describe('PreviewServerError', () => { it('should extend Error', () => { - expect(err).toEqual(jasmine.any(PreviewServerError)); - expect(err).toEqual(jasmine.any(Error)); + expect(err).toBeInstanceOf(PreviewServerError); + expect(err).toBeInstanceOf(Error); expect(Object.getPrototypeOf(err)).toBe(PreviewServerError.prototype); }); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-server-factory.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-server-factory.spec.ts index abfa0ab6d6..1db3aa2685 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-server-factory.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/preview-server-factory.spec.ts @@ -229,7 +229,7 @@ describe('PreviewServerFactory', () => { expect(prsAddCommentSpy).toHaveBeenCalledTimes(2); expect(prs).toBe(allCalls[1].object); - expect(prs).toEqual(jasmine.any(GithubPullRequests)); + expect(prs).toBeInstanceOf(GithubPullRequests); expect(prs.repoSlug).toBe('organisation/repo'); }); @@ -301,9 +301,8 @@ describe('PreviewServerFactory', () => { let bvGetSignificantFilesChangedSpy: jasmine.Spy; beforeEach(() => { - bvGetPrIsTrustedSpy = spyOn(buildVerifier, 'getPrIsTrusted').and.returnValue(Promise.resolve(true)); - bvGetSignificantFilesChangedSpy = spyOn(buildVerifier, 'getSignificantFilesChanged'). - and.returnValue(Promise.resolve(true)); + bvGetPrIsTrustedSpy = spyOn(buildVerifier, 'getPrIsTrusted').and.resolveTo(true); + bvGetSignificantFilesChangedSpy = spyOn(buildVerifier, 'getSignificantFilesChanged').and.resolveTo(true); }); @@ -330,7 +329,7 @@ describe('PreviewServerFactory', () => { it('should respond appropriately if the PR did not touch any significant files', async () => { - bvGetSignificantFilesChangedSpy.and.returnValue(Promise.resolve(false)); + bvGetSignificantFilesChangedSpy.and.resolveTo(false); const expectedResponse = {canHavePublicPreview: false, reason: 'No significant files touched.'}; const expectedLog = `PR:${pr} - Cannot have a public preview, because it did not touch any significant files.`; @@ -344,7 +343,7 @@ describe('PreviewServerFactory', () => { it('should respond appropriately if the PR is not automatically verifiable as "trusted"', async () => { - bvGetPrIsTrustedSpy.and.returnValue(Promise.resolve(false)); + bvGetPrIsTrustedSpy.and.resolveTo(false); const expectedResponse = {canHavePublicPreview: false, reason: 'Not automatically verifiable as "trusted".'}; const expectedLog = @@ -371,7 +370,7 @@ describe('PreviewServerFactory', () => { it('should respond with error if `getSignificantFilesChanged()` fails', async () => { - bvGetSignificantFilesChangedSpy.and.callFake(() => Promise.reject('getSignificantFilesChanged error')); + bvGetSignificantFilesChangedSpy.and.rejectWith('getSignificantFilesChanged error'); await agent.get(url).expect(500, 'getSignificantFilesChanged error'); expect(loggerErrorSpy).toHaveBeenCalledWith('Previewability check error', 'getSignificantFilesChanged error'); @@ -379,11 +378,10 @@ describe('PreviewServerFactory', () => { it('should respond with error if `getPrIsTrusted()` fails', async () => { - const error = new Error('getPrIsTrusted error'); - bvGetPrIsTrustedSpy.and.callFake(() => { throw error; }); + bvGetPrIsTrustedSpy.and.throwError('getPrIsTrusted error'); await agent.get(url).expect(500, 'getPrIsTrusted error'); - expect(loggerErrorSpy).toHaveBeenCalledWith('Previewability check error', error); + expect(loggerErrorSpy).toHaveBeenCalledWith('Previewability check error', new Error('getPrIsTrusted error')); }); }); @@ -496,7 +494,7 @@ describe('PreviewServerFactory', () => { // Note it is important to put the `reject` into `and.callFake`; // If you just `and.returnValue` the rejected promise // then you get an "unhandled rejection" message in the console. - getGithubInfoSpy.and.callFake(() => Promise.reject('Test Error')); + getGithubInfoSpy.and.rejectWith('Test Error'); await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); expect(downloadBuildArtifactSpy).not.toHaveBeenCalled(); @@ -517,7 +515,7 @@ describe('PreviewServerFactory', () => { }); it('should fail if the artifact fetch request fails', async () => { - downloadBuildArtifactSpy.and.callFake(() => Promise.reject('Test Error')); + downloadBuildArtifactSpy.and.rejectWith('Test Error'); await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); expect(downloadBuildArtifactSpy).toHaveBeenCalled(); @@ -526,7 +524,7 @@ describe('PreviewServerFactory', () => { }); it('should fail if verifying the PR fails', async () => { - getPrIsTrustedSpy.and.callFake(() => Promise.reject('Test Error')); + getPrIsTrustedSpy.and.rejectWith('Test Error'); await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); expect(downloadBuildArtifactSpy).toHaveBeenCalled(); @@ -535,7 +533,7 @@ describe('PreviewServerFactory', () => { }); it('should fail if creating the preview build fails', async () => { - createBuildSpy.and.callFake(() => Promise.reject('Test Error')); + createBuildSpy.and.rejectWith('Test Error'); await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); expect(downloadBuildArtifactSpy).toHaveBeenCalled(); @@ -604,7 +602,7 @@ describe('PreviewServerFactory', () => { it('should propagate errors from BuildVerifier', async () => { - bvGetPrIsTrustedSpy.and.callFake(() => Promise.reject('Test')); + bvGetPrIsTrustedSpy.and.rejectWith('Test'); await createRequest(+pr).expect(500, 'Test'); @@ -614,7 +612,9 @@ describe('PreviewServerFactory', () => { it('should call \'BuildCreator#updatePrVisibility()\' with the correct arguments', async () => { - bvGetPrIsTrustedSpy.and.callFake((pr2: number) => Promise.resolve(pr2 === 42)); + bvGetPrIsTrustedSpy. + withArgs(24).and.resolveTo(false). + withArgs(42).and.resolveTo(true); await createRequest(24); expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith(24, false); @@ -625,7 +625,7 @@ describe('PreviewServerFactory', () => { it('should propagate errors from BuildCreator', async () => { - bcUpdatePrVisibilitySpy.and.callFake(() => Promise.reject('Test')); + bcUpdatePrVisibilitySpy.and.rejectWith('Test'); await createRequest(+pr).expect(500, 'Test'); }); @@ -633,7 +633,9 @@ describe('PreviewServerFactory', () => { describe('on success', () => { it('should respond with 200 (action: undefined)', async () => { - bvGetPrIsTrustedSpy.and.returnValues(Promise.resolve(true), Promise.resolve(false)); + bvGetPrIsTrustedSpy. + withArgs(2).and.resolveTo(false). + withArgs(4).and.resolveTo(true); const reqs = [4, 2].map(num => createRequest(num).expect(200, http.STATUS_CODES[200])); await Promise.all(reqs); @@ -641,7 +643,9 @@ describe('PreviewServerFactory', () => { it('should respond with 200 (action: labeled)', async () => { - bvGetPrIsTrustedSpy.and.returnValues(Promise.resolve(true), Promise.resolve(false)); + bvGetPrIsTrustedSpy. + withArgs(2).and.resolveTo(false). + withArgs(4).and.resolveTo(true); const reqs = [4, 2].map(num => createRequest(num, 'labeled').expect(200, http.STATUS_CODES[200])); await Promise.all(reqs); @@ -649,7 +653,9 @@ describe('PreviewServerFactory', () => { it('should respond with 200 (action: unlabeled)', async () => { - bvGetPrIsTrustedSpy.and.returnValues(Promise.resolve(true), Promise.resolve(false)); + bvGetPrIsTrustedSpy. + withArgs(2).and.resolveTo(false). + withArgs(4).and.resolveTo(true); const reqs = [4, 2].map(num => createRequest(num, 'unlabeled').expect(200, http.STATUS_CODES[200])); await Promise.all(reqs); diff --git a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/utils.spec.ts b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/utils.spec.ts index 8be6ce6b49..993225711c 100644 --- a/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/utils.spec.ts +++ b/aio/aio-builds-setup/dockerbuild/scripts-js/test/preview-server/utils.spec.ts @@ -39,7 +39,7 @@ describe('preview-server/utils', () => { throwRequestError(505, 'ERROR MESSAGE', request); } catch (error) { caught = true; - expect(error).toEqual(jasmine.any(PreviewServerError)); + expect(error).toBeInstanceOf(PreviewServerError); expect(error.status).toEqual(505); expect(error.message).toEqual(`ERROR MESSAGE in request: POST some.domain.com/path "The request body"`); }