diff --git a/app/reducers/settingsUI.ts b/app/reducers/settingsUI.ts index cf598a0..6ace75d 100644 --- a/app/reducers/settingsUI.ts +++ b/app/reducers/settingsUI.ts @@ -16,7 +16,7 @@ export type SettingsUIState = Readonly<{ tlsClientOverrideAuthorityError: boolean; }>; -const initialSettingsUIState: SettingsUIState = { +export const initialSettingsUIState: SettingsUIState = { endpointRequired: false, endpointError: false, protoDiscoveryRootError: false, diff --git a/package-lock.json b/package-lock.json index 59785d8..da80ac4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -193,6 +193,15 @@ "integrity": "sha1-YPpDXOJL/VuhB7jSqAeWrq86j0U=", "dev": true }, + "@types/webdriverio": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/@types/webdriverio/-/webdriverio-4.8.4.tgz", + "integrity": "sha512-9klmCAyS+HWYw/xSIk8sD5jAi250hvY2Hziidwor9CilDRxbcahkEVO//0oPgNGl9On1Z75tTIi9jY57M3NVNw==", + "dev": true, + "requires": { + "@types/node": "8.0.22" + } + }, "@types/webfontloader": { "version": "1.6.28", "resolved": "https://registry.npmjs.org/@types/webfontloader/-/webfontloader-1.6.28.tgz", diff --git a/package.json b/package.json index 5e55644..75c1f47 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "main": "main.js", "scripts": { "test": "cross-env NODE_ENV=test node --trace-warnings ./test/runTests.js", - "test-all": "npm run test && npm run build && npm run test-e2e", + "test-all": "npm run test && npm run test-e2e", "test-watch": "npm test -- --watch", "test-e2e": "cross-env NODE_ENV=test node --trace-warnings ./test/runTests.js e2e", "hot-server": "cross-env NODE_ENV=development node --max_old_space_size=2096 server.js", @@ -138,6 +138,7 @@ "@types/text-encoding": "0.0.31", "@types/universal-analytics": "^0.4.1", "@types/valid-url": "^1.0.2", + "@types/webdriverio": "^4.8.4", "@types/webfontloader": "^1.6.28", "asar": "^0.13.0", "boiler-room-custodian": "^0.6.2", diff --git a/test/e2e/e2e.spec.ts b/test/e2e/e2e.spec.ts index 24a0388..7217f7c 100644 --- a/test/e2e/e2e.spec.ts +++ b/test/e2e/e2e.spec.ts @@ -1,102 +1,133 @@ -// import * as electronPath from "electron"; -// import * as path from "path"; +/* tslint:disable:no-console */ +import * as path from 'path'; -// const { Application } = require("spectron"); // tslint:disable-line +import { Application } from 'spectron'; // const delay = (time: number) => new Promise((resolve) => setTimeout(resolve, time)); -// describe("main window", function spec() { -// let app: any; -// beforeAll(async () => { -// app = new Application({ -// path: electronPath, -// args: [path.join(__dirname, "..", "..", "app")], -// }); -// return app.start(); -// }); - -// afterAll(() => { -// if (app && app.isRunning()) { -// return app.stop(); -// } -// }); - -// const findCounter = () => app.client.element("[data-tid='counter']"); - -// const findButtons = async () => { -// const { value } = await app.client.elements("[data-tclass='btn']"); -// return value.map((btn: any) => btn.ELEMENT); -// }; - -// it("should open window", async () => { -// const { client, browserWindow } = app; - -// await client.waitUntilWindowLoaded(); -// await delay(500); -// const title = await browserWindow.getTitle(); -// expect(title).toBe("Dragoman"); -// }); - -// it("should navigate to Counter by "to Counter" link", async () => { -// const { client } = app; - -// await client.click("[data-tid="container"] > a"); -// await delay(100); -// expect(await findCounter().getText()).toBe("0"); -// }); - -// it("should display updated count after increment button click", async () => { -// const { client } = app; - -// const buttons = await findButtons(); -// await client.elementIdClick(buttons[0]); // + -// expect(await findCounter().getText()).toBe("1"); -// }); - -// it("should display updated count after descrement button click", async () => { -// const { client } = app; - -// const buttons = await findButtons(); -// await client.elementIdClick(buttons[1]); // - -// expect(await findCounter().getText()).toBe("0"); -// }); - -// it("shouldn\"t change if even and if odd button clicked", async () => { -// const { client } = app; - -// const buttons = await findButtons(); -// await client.elementIdClick(buttons[2]); // odd -// expect(await findCounter().getText()).toBe("0"); -// }); - -// it("should change if odd and if odd button clicked", async () => { -// const { client } = app; - -// const buttons = await findButtons(); -// await client.elementIdClick(buttons[0]); // + -// await client.elementIdClick(buttons[2]); // odd -// expect(await findCounter().getText()).toBe("2"); -// }); - -// it("should change if async button clicked and a second later", async () => { -// const { client } = app; - -// const buttons = await findButtons(); -// await client.elementIdClick(buttons[3]); // async -// expect(await findCounter().getText()).toBe("2"); -// await delay(1000); -// expect(await findCounter().getText()).toBe("3"); -// }); - -// it("should navigate to home using back button", async () => { -// const { client } = app; -// await client.element( -// "[data-tid="backButton"] > a" -// ).click(); -// await delay(100); - -// expect( -// await client.isExisting("[data-tid="container"]") -// ).toBe(true); -// }); -// }); +describe('main window', function spec() { + let app: Application; + beforeAll(() => { + let pathToBinary; + + switch (process.platform) { + case 'linux': + pathToBinary = path.join(__dirname, '../../release/linux-unpacked/dragoman'); + break; + + case 'darwin': + pathToBinary = path.join(__dirname, '../../release/mac/Dragoman.app/Contents/MacOS/Dragoman'); + break; + + case 'win32': + pathToBinary = path.join(__dirname, '../release/win-unpacked/Dragoman.exe'); + break; + + default: + throw new Error('Path to the built binary needs to be defined for this platform in test/index.js'); + } + + app = new Application({ + path: pathToBinary, + }); + return app.start(); + }); + + afterAll(() => { + if (app && app.isRunning()) { + return app.stop(); + } else { + return; + } + }); + + // const findCounter = () => app.client.element('[data-tid='counter']'); + + // const findButtons = async () => { + // const { value } = await app.client.elements('[data-tclass='btn']'); + // return value.map((btn: any) => btn.ELEMENT); + // }; + + it('should open window', () => { + // delay(1000); + const { client, browserWindow } = app; + + return client.waitUntilWindowLoaded() + .then(() => { return browserWindow.webContents.isDevToolsOpened(); }) + .then((isDevToolsOpen) => { + expect(isDevToolsOpen).toBe(false); + }); + }); + + it('should have a title', async () => { + const { client, browserWindow } = app; + + await client.waitUntilWindowLoaded(); + const title = await browserWindow.getTitle(); + console.error(title); + expect(title).toBe('Dragoman'); + }); + + // it('should navigate to Counter by 'to Counter' link', async () => { + // const { client } = app; + + // await client.click('[data-tid='container'] > a'); + // await delay(100); + // expect(await findCounter().getText()).toBe('0'); + // }); + + // it('should display updated count after increment button click', async () => { + // const { client } = app; + + // const buttons = await findButtons(); + // await client.elementIdClick(buttons[0]); // + + // expect(await findCounter().getText()).toBe('1'); + // }); + + // it('should display updated count after descrement button click', async () => { + // const { client } = app; + + // const buttons = await findButtons(); + // await client.elementIdClick(buttons[1]); // - + // expect(await findCounter().getText()).toBe('0'); + // }); + + // it('shouldn\'t change if even and if odd button clicked', async () => { + // const { client } = app; + + // const buttons = await findButtons(); + // await client.elementIdClick(buttons[2]); // odd + // expect(await findCounter().getText()).toBe('0'); + // }); + + // it('should change if odd and if odd button clicked', async () => { + // const { client } = app; + + // const buttons = await findButtons(); + // await client.elementIdClick(buttons[0]); // + + // await client.elementIdClick(buttons[2]); // odd + // expect(await findCounter().getText()).toBe('2'); + // }); + + // it('should change if async button clicked and a second later', async () => { + // const { client } = app; + + // const buttons = await findButtons(); + // await client.elementIdClick(buttons[3]); // async + // expect(await findCounter().getText()).toBe('2'); + // await delay(1000); + // expect(await findCounter().getText()).toBe('3'); + // }); + + // it('should navigate to home using back button', async () => { + // const { client } = app; + // await client.element( + // '[data-tid='backButton'] > a' + // ).click(); + // await delay(100); + + // expect( + // await client.isExisting('[data-tid='container']') + // ).toBe(true); + // }); +}); diff --git a/test/reducers/settingsData.spec.ts b/test/reducers/settingsData.spec.ts new file mode 100644 index 0000000..988aa2d --- /dev/null +++ b/test/reducers/settingsData.spec.ts @@ -0,0 +1,76 @@ +import settingsData, { initialSettingsDataState } from '../../app/reducers/settingsData'; +import * as settingsDataActions from '../../app/actions/settingsData'; + +describe('settings UI reducer', () => { + describe('endpoint error', () => { + it('should handle initial state', () => { + expect(settingsData(undefined, { type: 'UNKNOWN', payload: {} })).toEqual(initialSettingsDataState); + }); + + it('should handle SET_PROTO_DISCOVERY_ROOT', () => { + expect(settingsData(undefined, settingsDataActions.setProtoDiscoveryRoot('/Users')).protoDiscoveryRoot).toEqual('/Users'); + }); + + it('should handle SET_ENDPOINT', () => { + expect(settingsData(undefined, settingsDataActions.setEndpoint('host:50')).endpoint).toEqual('host:50'); + }); + + it('should handle SET_CONFIG_SET_PATH_ERROR', () => { + expect(settingsData(undefined, settingsDataActions.setConfigSetPath('/Users')).configSetPath).toEqual('/Users'); + }); + + it('should handle SET_CONFIG_NAME', () => { + expect(settingsData(undefined, settingsDataActions.setConfigName('staging')).configName).toEqual('staging'); + }); + + it('should handle SET_DEADLINE_MS', () => { + expect(settingsData(undefined, settingsDataActions.setDeadlineMs(50)).deadlineMs).toEqual(50); + }); + + it('should handle SET_ADD_PROTOC_INCLUDES', () => { + expect(settingsData(undefined, settingsDataActions.setAddProtocIncludes('/Users,/Users/peteboothroyd')).addProtocIncludes).toEqual('/Users,/Users/peteboothroyd'); + }); + + it('should handle SET_OAUTH_REFRESH_TOKEN_ENDPOINT_URL', () => { + expect(settingsData(undefined, settingsDataActions.setOauthRefreshTokenEndpointUrl('https://improbable.io')).oauthRefreshTokenEndpointUrl).toEqual('https://improbable.io'); + }); + + it('should handle SET_OAUTH_CLIENT_ID', () => { + expect(settingsData(undefined, settingsDataActions.setOauthClientId('id')).oauthClientId).toEqual('id'); + }); + + it('should handle SET_OAUTH_CLIENT_SECRET', () => { + expect(settingsData(undefined, settingsDataActions.setOauthClientSecret('secret')).oauthClientSecret).toEqual('secret'); + }); + + it('should handle SET_OAUTH_REFRESH_TOKEN_PATH', () => { + expect(settingsData(undefined, settingsDataActions.setOauthRefreshTokenPath('/Users')).oauthRefreshTokenPath).toEqual('/Users'); + }); + + it('should handle SET_OAUTH_ACCESS_TOKEN_PATH', () => { + expect(settingsData(undefined, settingsDataActions.setOauthAccessTokenPath('/Users')).oauthAccessTokenPath).toEqual('/Users'); + }); + + it('should handle SET_USE_TLS', () => { + expect(settingsData(undefined, settingsDataActions.setUseTls(true)).useTls).toEqual(true); + }); + + it('should handle SET_TLS_CA_CERT_PATH', () => { + expect(settingsData(undefined, settingsDataActions.setTlsCaCertPath('/Users')).tlsCaCertPath).toEqual('/Users'); + }); + + it('should handle SET_TLS_CLIENT_KEY_PATH', () => { + expect(settingsData(undefined, settingsDataActions.setTlsClientKeyPath('/Users')).tlsClientKeyPath).toEqual('/Users'); + }); + + it('should handle SET_TLS_CLIENT_CERT_PATH', () => { + expect(settingsData(undefined, settingsDataActions.setTlsClientCertPath('/Users')).tlsClientCertPath).toEqual('/Users'); + }); + + it('should handle SET_TLS_CLIENT_OVERRRIDE_AUTHORITY', () => { + expect(settingsData(undefined, settingsDataActions.setTlsClientOverrideAuthority('authority')).tlsClientOverrideAuthority).toEqual('authority'); + }); + + // TODO: Add tests for importing polyglot configs from an example config file + }); +}); diff --git a/test/reducers/settingsUI.spec.ts b/test/reducers/settingsUI.spec.ts index dfd9395..a1e0c95 100644 --- a/test/reducers/settingsUI.spec.ts +++ b/test/reducers/settingsUI.spec.ts @@ -1,22 +1,50 @@ -import settingsUI from '../../app/reducers/settingsUI'; -// import * as settingsUIActions from '../../app/actions/settingsUI'; +import settingsUI, {initialSettingsUIState} from '../../app/reducers/settingsUI'; +import * as settingsUIActions from '../../app/actions/settingsUI'; describe('settings UI reducer', () => { describe('endpoint error', () => { it('should handle initial state', () => { - expect(settingsUI(undefined, { type: 'unknown', payload: {} }).endpointError).toBe(false); + expect(settingsUI(undefined, { type: 'UNKNOWN', payload: {} })).toEqual(initialSettingsUIState); }); - // it('should handle INCREMENT_COUNTER', () => { - // expect(counter(1, increment())).toBe(2); - // }); + it('should handle SET_ENDPOINT_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setEndpointError(true)).endpointError).toEqual(true); + }); - // it('should handle DECREMENT_COUNTER', () => { - // expect(counter(1, decrement())).toBe(0); - // }); + it('should handle SET_ENDPOINT_REQUIRED', () => { + expect(settingsUI(undefined, settingsUIActions.setEndpointRequired(true)).endpointRequired).toEqual(true); + }); - // it('should handle unknown action type', () => { - // expect(counter(1, { type: 'unknown' })).toBe(1); - // }); + it('should handle SET_CONFIG_SET_PATH_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setConfigSetPathError(true)).configSetPathError).toEqual(true); + }); + + it('should handle SET_ADD_PROTOC_INCLUDES_ERRORS', () => { + expect(settingsUI(undefined, settingsUIActions.setAddProtocIncludesError([true, false])).addProtocIncludesErrors).toEqual([true, false]); + }); + + it('should handle SET_OAUTH_REFRESH_TOKEN_ENDPOINT_URL_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setOauthRefreshTokenEndpointUrlError(true)).oauthRefreshTokenEndpointUrlError).toEqual(true); + }); + + it('should handle SET_OAUTH_REFRESH_TOKEN_PATH_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setOauthRefreshTokenPathError(true)).oauthRefreshTokenPathError).toEqual(true); + }); + + it('should handle SET_OAUTH_ACCESS_TOKEN_PATH_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setOauthAccessTokenPathError(true)).oauthAccessTokenPathError).toEqual(true); + }); + + it('should handle SET_TLS_CA_CERT_PATH_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setTlsCaCertPathError(true)).tlsCaCertPathError).toEqual(true); + }); + + it('should handle SET_TLS_CLIENT_KEY_PATH_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setTlsClientKeyPathError(true)).tlsClientKeyPathError).toEqual(true); + }); + + it('should handle SET_TLS_CLIENT_CERT_PATH_ERROR', () => { + expect(settingsUI(undefined, settingsUIActions.setTlsClientCertPathError(true)).tlsClientCertPathError).toEqual(true); + }); }); }); diff --git a/test/runTests.js b/test/runTests.js index ead06ec..eda1778 100644 --- a/test/runTests.js +++ b/test/runTests.js @@ -1,4 +1,4 @@ -const spawn = require('cross-spawn'); +const spawn = require('child_process').spawnSync; const path = require('path'); const s = `\\${path.sep}`; @@ -6,6 +6,6 @@ const pattern = process.argv[2] === 'e2e' ? `test${s}e2e${s}.+\\.spec\\.tsx?` : `test${s}(?!e2e${s})[^${s}]+${s}.+\\.spec\\.tsx?$`; -const result = spawn.sync(path.normalize('./node_modules/.bin/jest'), [pattern], { stdio: 'inherit' }); +const result = spawn(path.normalize('./node_modules/.bin/jest'), [pattern], { stdio: 'inherit' }); process.exit(result.status);