diff --git a/internals/flow/CSSModule.js.flow b/internals/flow/CSSModule.js.flow deleted file mode 100644 index 6bd2a54f..00000000 --- a/internals/flow/CSSModule.js.flow +++ /dev/null @@ -1,3 +0,0 @@ -// @flow - -declare export default { [key: string]: string } \ No newline at end of file diff --git a/internals/flow/WebpackAsset.js.flow b/internals/flow/WebpackAsset.js.flow deleted file mode 100644 index 37d49d3e..00000000 --- a/internals/flow/WebpackAsset.js.flow +++ /dev/null @@ -1,2 +0,0 @@ -// @flow -declare export default string diff --git a/internals/img/eslint-padded-90.png b/internals/img/eslint-padded-90.png deleted file mode 100644 index d3c59cba..00000000 Binary files a/internals/img/eslint-padded-90.png and /dev/null differ diff --git a/internals/img/eslint-padded.png b/internals/img/eslint-padded.png deleted file mode 100644 index d6f9a1af..00000000 Binary files a/internals/img/eslint-padded.png and /dev/null differ diff --git a/internals/img/eslint.png b/internals/img/eslint.png deleted file mode 100755 index 7fc0e980..00000000 Binary files a/internals/img/eslint.png and /dev/null differ diff --git a/internals/img/flow-padded-90.png b/internals/img/flow-padded-90.png deleted file mode 100644 index 3ee97f0c..00000000 Binary files a/internals/img/flow-padded-90.png and /dev/null differ diff --git a/internals/img/flow-padded.png b/internals/img/flow-padded.png deleted file mode 100644 index 35ebd029..00000000 Binary files a/internals/img/flow-padded.png and /dev/null differ diff --git a/internals/img/flow.png b/internals/img/flow.png deleted file mode 100755 index f4c4bed7..00000000 Binary files a/internals/img/flow.png and /dev/null differ diff --git a/internals/img/jest-padded-90.png b/internals/img/jest-padded-90.png deleted file mode 100644 index 1f942a87..00000000 Binary files a/internals/img/jest-padded-90.png and /dev/null differ diff --git a/internals/img/jest-padded.png b/internals/img/jest-padded.png deleted file mode 100644 index ff62dd02..00000000 Binary files a/internals/img/jest-padded.png and /dev/null differ diff --git a/internals/img/jest.png b/internals/img/jest.png deleted file mode 100644 index 3923b0bc..00000000 Binary files a/internals/img/jest.png and /dev/null differ diff --git a/internals/img/js-padded.png b/internals/img/js-padded.png deleted file mode 100644 index d1f0ba60..00000000 Binary files a/internals/img/js-padded.png and /dev/null differ diff --git a/internals/img/js.png b/internals/img/js.png deleted file mode 100755 index 7f492390..00000000 Binary files a/internals/img/js.png and /dev/null differ diff --git a/internals/img/npm.png b/internals/img/npm.png deleted file mode 100755 index 06c649a8..00000000 Binary files a/internals/img/npm.png and /dev/null differ diff --git a/internals/img/react-padded-90.png b/internals/img/react-padded-90.png deleted file mode 100644 index d10d9f28..00000000 Binary files a/internals/img/react-padded-90.png and /dev/null differ diff --git a/internals/img/react-padded.png b/internals/img/react-padded.png deleted file mode 100644 index a5f24293..00000000 Binary files a/internals/img/react-padded.png and /dev/null differ diff --git a/internals/img/react-router-padded-90.png b/internals/img/react-router-padded-90.png deleted file mode 100644 index 711d7412..00000000 Binary files a/internals/img/react-router-padded-90.png and /dev/null differ diff --git a/internals/img/react-router-padded.png b/internals/img/react-router-padded.png deleted file mode 100644 index a0c4ac95..00000000 Binary files a/internals/img/react-router-padded.png and /dev/null differ diff --git a/internals/img/react-router.png b/internals/img/react-router.png deleted file mode 100644 index a926678b..00000000 Binary files a/internals/img/react-router.png and /dev/null differ diff --git a/internals/img/react.png b/internals/img/react.png deleted file mode 100755 index b82579d5..00000000 Binary files a/internals/img/react.png and /dev/null differ diff --git a/internals/img/redux-padded-90.png b/internals/img/redux-padded-90.png deleted file mode 100644 index 7d96a6a6..00000000 Binary files a/internals/img/redux-padded-90.png and /dev/null differ diff --git a/internals/img/redux-padded.png b/internals/img/redux-padded.png deleted file mode 100644 index fd23430b..00000000 Binary files a/internals/img/redux-padded.png and /dev/null differ diff --git a/internals/img/redux.png b/internals/img/redux.png deleted file mode 100755 index cda220de..00000000 Binary files a/internals/img/redux.png and /dev/null differ diff --git a/internals/img/webpack-padded-90.png b/internals/img/webpack-padded-90.png deleted file mode 100644 index 4076d5bd..00000000 Binary files a/internals/img/webpack-padded-90.png and /dev/null differ diff --git a/internals/img/webpack-padded.png b/internals/img/webpack-padded.png deleted file mode 100644 index cc1d1a22..00000000 Binary files a/internals/img/webpack-padded.png and /dev/null differ diff --git a/internals/img/webpack.png b/internals/img/webpack.png deleted file mode 100755 index bc437f0b..00000000 Binary files a/internals/img/webpack.png and /dev/null differ diff --git a/internals/img/yarn-padded-90.png b/internals/img/yarn-padded-90.png deleted file mode 100644 index a08b53ba..00000000 Binary files a/internals/img/yarn-padded-90.png and /dev/null differ diff --git a/internals/img/yarn-padded.png b/internals/img/yarn-padded.png deleted file mode 100644 index ca85ee2f..00000000 Binary files a/internals/img/yarn-padded.png and /dev/null differ diff --git a/internals/img/yarn.png b/internals/img/yarn.png deleted file mode 100644 index f406a471..00000000 Binary files a/internals/img/yarn.png and /dev/null differ diff --git a/internals/scripts/.eslintrc b/internals/scripts/.eslintrc new file mode 100644 index 00000000..35dc618d --- /dev/null +++ b/internals/scripts/.eslintrc @@ -0,0 +1,8 @@ +{ + "rules": { + "no-console": "off", + "global-require": "off", + "import/no-dynamic-require": "off", + "import/no-extraneous-dependencies": "off" + } +} diff --git a/internals/scripts/BabelRegister.js b/internals/scripts/BabelRegister.js index bf41c5af..9608e76e 100644 --- a/internals/scripts/BabelRegister.js +++ b/internals/scripts/BabelRegister.js @@ -2,5 +2,5 @@ const path = require('path'); require('@babel/register')({ extensions: ['.es6', '.es', '.jsx', '.js', '.mjs', '.ts', '.tsx'], - cwd: path.join(__dirname, '..', '..'), + cwd: path.join(__dirname, '..', '..') }); diff --git a/internals/scripts/CheckBuildsExist.js b/internals/scripts/CheckBuildsExist.js new file mode 100644 index 00000000..802394c0 --- /dev/null +++ b/internals/scripts/CheckBuildsExist.js @@ -0,0 +1,30 @@ +// Check if the renderer and main bundles are built +import path from 'path'; +import chalk from 'chalk'; +import fs from 'fs'; + +const mainPath = path.join(__dirname, '..', '..', 'app', 'main.prod.js'); +const rendererPath = path.join( + __dirname, + '..', + '..', + 'app', + 'dist', + 'renderer.prod.js' +); + +if (!fs.existsSync(mainPath)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + 'The main process is not built yet. Build it by running "yarn build-main"' + ) + ); +} + +if (!fs.existsSync(rendererPath)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + 'The renderer process is not built yet. Build it by running "yarn build-renderer"' + ) + ); +} diff --git a/internals/scripts/CheckBuiltsExist.js b/internals/scripts/CheckBuiltsExist.js deleted file mode 100644 index 91510811..00000000 --- a/internals/scripts/CheckBuiltsExist.js +++ /dev/null @@ -1,28 +0,0 @@ -// @flow -// Check if the renderer and main bundles are built -import path from 'path'; -import chalk from 'chalk'; -import fs from 'fs'; - -function CheckBuildsExist() { - const mainPath = path.join(__dirname, '..', '..', 'app', 'main.prod.js'); - const rendererPath = path.join(__dirname, '..', '..', 'app', 'dist', 'renderer.prod.js'); - - if (!fs.existsSync(mainPath)) { - throw new Error( - chalk.whiteBright.bgRed.bold( - 'The main process is not built yet. Build it by running "npm run build-main"' - ) - ); - } - - if (!fs.existsSync(rendererPath)) { - throw new Error( - chalk.whiteBright.bgRed.bold( - 'The renderer process is not built yet. Build it by running "npm run build-renderer"' - ) - ); - } -} - -CheckBuildsExist(); diff --git a/internals/scripts/CheckNativeDep.js b/internals/scripts/CheckNativeDep.js index 578b6bed..1acf39ec 100644 --- a/internals/scripts/CheckNativeDep.js +++ b/internals/scripts/CheckNativeDep.js @@ -1,60 +1,49 @@ -// @flow import fs from 'fs'; import chalk from 'chalk'; import { execSync } from 'child_process'; import { dependencies } from '../../package.json'; -(() => { - if (!dependencies) return; - +if (dependencies) { const dependenciesKeys = Object.keys(dependencies); const nativeDeps = fs .readdirSync('node_modules') - .filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`)); - + .filter(folder => fs.existsSync(`node_modules/${folder}/binding.gyp`)); try { // Find the reason for why the dependency is installed. If it is installed // because of a devDependency then that is okay. Warn when it is installed // because of a dependency - const dependenciesObject = JSON.parse( + const { dependencies: dependenciesObject } = JSON.parse( execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString() ); - const rootDependencies = Object.keys(dependenciesObject.dependencies); - const filteredRootDependencies = rootDependencies.filter((rootDependency) => + const rootDependencies = Object.keys(dependenciesObject); + const filteredRootDependencies = rootDependencies.filter(rootDependency => dependenciesKeys.includes(rootDependency) ); - if (filteredRootDependencies.length > 0) { const plural = filteredRootDependencies.length > 1; console.log(` - -${chalk.whiteBright.bgYellow.bold('Webpack does not work with native dependencies.')} + ${chalk.whiteBright.bgYellow.bold( + 'Webpack does not work with native dependencies.' + )} ${chalk.bold(filteredRootDependencies.join(', '))} ${ plural ? 'are native dependencies' : 'is a native dependency' } and should be installed inside of the "./app" folder. - - -First uninstall the packages from "./package.json": -${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')} - -${chalk.bold('Then, instead of installing the package to the root "./package.json":')} -${chalk.whiteBright.bgRed.bold('npm install your-package --save')} - -${chalk.bold('Install the package to "./app/package.json"')} -${chalk.whiteBright.bgGreen.bold('cd ./app && npm install your-package --save')} - - -Read more about native dependencies at: + First, uninstall the packages from "./package.json": +${chalk.whiteBright.bgGreen.bold('yarn remove your-package')} + ${chalk.bold( + 'Then, instead of installing the package to the root "./package.json":' + )} +${chalk.whiteBright.bgRed.bold('yarn add your-package')} + ${chalk.bold('Install the package to "./app/package.json"')} +${chalk.whiteBright.bgGreen.bold('cd ./app && yarn add your-package')} + Read more about native dependencies at: ${chalk.bold( - 'https://github.com/chentsulin/electron-react-boilerplate/wiki/Module-Structure----Two-package.json-Structure' + 'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure' )} - - -`); - + `); process.exit(1); } } catch (e) { console.log('Native dependencies could not be checked'); } -})(); +} diff --git a/internals/scripts/CheckNodeEnv.js b/internals/scripts/CheckNodeEnv.js index b2f50bcf..8acca0a2 100644 --- a/internals/scripts/CheckNodeEnv.js +++ b/internals/scripts/CheckNodeEnv.js @@ -1,7 +1,6 @@ -// @flow import chalk from 'chalk'; -export default function CheckNodeEnv(expectedEnv: string) { +export default function CheckNodeEnv(expectedEnv) { if (!expectedEnv) { throw new Error('"expectedEnv" not set'); } diff --git a/internals/scripts/CheckPortInUse.js b/internals/scripts/CheckPortInUse.js index a61be941..982ca49e 100644 --- a/internals/scripts/CheckPortInUse.js +++ b/internals/scripts/CheckPortInUse.js @@ -1,19 +1,16 @@ -// @flow import chalk from 'chalk'; import detectPort from 'detect-port'; -(function CheckPortInUse() { - const port: string = process.env.PORT || '1212'; +const port = process.env.PORT || '1212'; - detectPort(port, (err: ?Error, availablePort: number) => { - if (port !== String(availablePort)) { - throw new Error( - chalk.whiteBright.bgRed.bold( - `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm run dev` - ) - ); - } else { - process.exit(0); - } - }); -})(); +detectPort(port, (err, availablePort) => { + if (port !== String(availablePort)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 yarn dev` + ) + ); + } else { + process.exit(0); + } +}); diff --git a/internals/scripts/CheckYarn.js b/internals/scripts/CheckYarn.js new file mode 100644 index 00000000..aa5be8d1 --- /dev/null +++ b/internals/scripts/CheckYarn.js @@ -0,0 +1,5 @@ +if (!/yarn\.js$/.test(process.env.npm_execpath || '')) { + console.warn( + "\u001b[33mYou don't seem to be using yarn. This could produce unexpected results.\u001b[39m" + ); +} diff --git a/internals/scripts/DeleteSourceMaps.js b/internals/scripts/DeleteSourceMaps.js new file mode 100644 index 00000000..91bbb3a1 --- /dev/null +++ b/internals/scripts/DeleteSourceMaps.js @@ -0,0 +1,7 @@ +import path from 'path'; +import rimraf from 'rimraf'; + +export default function deleteSourceMaps() { + rimraf.sync(path.join(__dirname, '../../app/dist/*.js.map')); + rimraf.sync(path.join(__dirname, '../../app/*.js.map')); +} diff --git a/internals/scripts/ElectronRebuild.js b/internals/scripts/ElectronRebuild.js index adb858af..2bff677c 100644 --- a/internals/scripts/ElectronRebuild.js +++ b/internals/scripts/ElectronRebuild.js @@ -1,19 +1,22 @@ -// @flow import path from 'path'; import { execSync } from 'child_process'; import fs from 'fs'; -import dependencies from '../../app/package.json'; +import { dependencies } from '../../app/package.json'; const nodeModulesPath = path.join(__dirname, '..', '..', 'app', 'node_modules'); -if (Object.keys(dependencies || {}).length > 0 && fs.existsSync(nodeModulesPath)) { +if ( + Object.keys(dependencies || {}).length > 0 && + fs.existsSync(nodeModulesPath) +) { const electronRebuildCmd = '../node_modules/.bin/electron-rebuild --parallel --force --types prod,dev,optional --module-dir .'; - const cmd = - process.platform === 'win32' ? electronRebuildCmd.replace(/\//g, '\\') : electronRebuildCmd; - + process.platform === 'win32' + ? electronRebuildCmd.replace(/\//g, '\\') + : electronRebuildCmd; execSync(cmd, { cwd: path.join(__dirname, '..', '..', 'app'), + stdio: 'inherit' }); } diff --git a/internals/scripts/RunTests.js b/internals/scripts/RunTests.js deleted file mode 100644 index 45e0cd28..00000000 --- a/internals/scripts/RunTests.js +++ /dev/null @@ -1,13 +0,0 @@ -import spawn from 'cross-spawn'; -import path from 'path'; - -const pattern = - process.argv[2] === 'e2e' ? 'test/e2e/.+\\.spec\\.js' : 'test/(?!e2e/)[^/]+/.+\\.spec\\.js$'; - -const result = spawn.sync( - path.normalize('./node_modules/.bin/jest'), - [pattern, ...process.argv.slice(2)], - { stdio: 'inherit' } -); - -process.exit(result.status); diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 00000000..9adaad74 --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,13 @@ +{ + "extends": "plugin:testcafe/recommended", + "env": { + "jest/globals": true + }, + "plugins": ["jest", "testcafe"], + "rules": { + "jest/no-disabled-tests": "warn", + "jest/no-focused-tests": "error", + "jest/no-identical-title": "error", + "no-console": "off" + } +} diff --git a/test/actions/__snapshots__/counter.spec.ts.snap b/test/actions/__snapshots__/counter.spec.ts.snap new file mode 100644 index 00000000..dc692275 --- /dev/null +++ b/test/actions/__snapshots__/counter.spec.ts.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`actions should decrement should create decrement action 1`] = ` +Object { + "type": "DECREMENT_COUNTER", +} +`; + +exports[`actions should increment should create increment action 1`] = ` +Object { + "type": "INCREMENT_COUNTER", +} +`; diff --git a/test/actions/counter.spec.ts b/test/actions/counter.spec.ts new file mode 100644 index 00000000..0bdd6ea5 --- /dev/null +++ b/test/actions/counter.spec.ts @@ -0,0 +1,45 @@ +import { spy } from 'sinon'; +import * as actions from '../../app/actions/counter'; + +describe('actions', () => { + it('should increment should create increment action', () => { + expect(actions.increment()).toMatchSnapshot(); + }); + + it('should decrement should create decrement action', () => { + expect(actions.decrement()).toMatchSnapshot(); + }); + + it('should incrementIfOdd should create increment action', () => { + const fn = actions.incrementIfOdd(); + expect(fn).toBeInstanceOf(Function); + const dispatch = spy(); + const getState = () => ({ counter: 1 }); + fn(dispatch, getState); + expect(dispatch.calledWith({ type: actions.INCREMENT_COUNTER })).toBe(true); + }); + + it('should incrementIfOdd shouldnt create increment action if counter is even', () => { + const fn = actions.incrementIfOdd(); + const dispatch = spy(); + const getState = () => ({ counter: 2 }); + fn(dispatch, getState); + expect(dispatch.called).toBe(false); + }); + + // There's no nice way to test this at the moment... + it('should incrementAsync', () => { + return new Promise(resolve => { + const fn = actions.incrementAsync(1); + expect(fn).toBeInstanceOf(Function); + const dispatch = spy(); + fn(dispatch); + setTimeout(() => { + expect(dispatch.calledWith({ type: actions.INCREMENT_COUNTER })).toBe( + true + ); + resolve(); + }, 5); + }); + }); +}); diff --git a/test/components/Counter.spec.tsx b/test/components/Counter.spec.tsx new file mode 100644 index 00000000..05fda86a --- /dev/null +++ b/test/components/Counter.spec.tsx @@ -0,0 +1,71 @@ +/* eslint react/jsx-props-no-spreading: off */ +import { spy } from 'sinon'; +import React from 'react'; +import Enzyme, { shallow } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { BrowserRouter as Router } from 'react-router-dom'; +import renderer from 'react-test-renderer'; +import Counter from '../../app/components/Counter'; + +Enzyme.configure({ adapter: new Adapter() }); + +function setup() { + const actions = { + increment: spy(), + incrementIfOdd: spy(), + incrementAsync: spy(), + decrement: spy() + }; + const component = shallow(); + return { + component, + actions, + buttons: component.find('button'), + p: component.find('.counter') + }; +} + +describe('Counter component', () => { + it('should should display count', () => { + const { p } = setup(); + expect(p.text()).toMatch(/^1$/); + }); + + it('should first button should call increment', () => { + const { buttons, actions } = setup(); + buttons.at(0).simulate('click'); + expect(actions.increment.called).toBe(true); + }); + + it('should match exact snapshot', () => { + const { actions } = setup(); + const counter = ( +
+ + + +
+ ); + const tree = renderer.create(counter).toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('should second button should call decrement', () => { + const { buttons, actions } = setup(); + buttons.at(1).simulate('click'); + expect(actions.decrement.called).toBe(true); + }); + + it('should third button should call incrementIfOdd', () => { + const { buttons, actions } = setup(); + buttons.at(2).simulate('click'); + expect(actions.incrementIfOdd.called).toBe(true); + }); + + it('should fourth button should call incrementAsync', () => { + const { buttons, actions } = setup(); + buttons.at(3).simulate('click'); + expect(actions.incrementAsync.called).toBe(true); + }); +}); diff --git a/test/components/__snapshots__/Counter.spec.tsx.snap b/test/components/__snapshots__/Counter.spec.tsx.snap new file mode 100644 index 00000000..2c98227d --- /dev/null +++ b/test/components/__snapshots__/Counter.spec.tsx.snap @@ -0,0 +1,67 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Counter component should match exact snapshot 1`] = ` +
+
+
+ + + +
+
+ 1 +
+
+ + + + +
+
+
+`; diff --git a/test/containers/CounterPage.spec.tsx b/test/containers/CounterPage.spec.tsx new file mode 100644 index 00000000..37d5b981 --- /dev/null +++ b/test/containers/CounterPage.spec.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import Enzyme, { mount } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { Provider } from 'react-redux'; +import { createBrowserHistory } from 'history'; +import { ConnectedRouter } from 'connected-react-router'; +import CounterPage from '../../app/containers/CounterPage'; +import { configureStore } from '../../app/store/configureStore'; + +Enzyme.configure({ adapter: new Adapter() }); + +function setup(initialState = {}) { + const store = configureStore(initialState); + const history = createBrowserHistory(); + const provider = ( + + + + + + ); + const app = mount(provider); + return { + app, + buttons: app.find('button'), + p: app.find('.counter') + }; +} + +describe('containers', () => { + describe('App', () => { + it('should display initial count', () => { + const { p } = setup(); + expect(p.text()).toMatch(/^0$/); + }); + + it('should display updated count after increment button click', () => { + const { buttons, p } = setup(); + buttons.at(0).simulate('click'); + expect(p.text()).toMatch(/^1$/); + }); + + it('should display updated count after decrement button click', () => { + const { buttons, p } = setup(); + buttons.at(1).simulate('click'); + expect(p.text()).toMatch(/^-1$/); + }); + + it('shouldnt change if even and if odd button clicked', () => { + const { buttons, p } = setup(); + buttons.at(2).simulate('click'); + expect(p.text()).toMatch(/^0$/); + }); + + it('should change if odd and if odd button clicked', () => { + const { buttons, p } = setup({ counter: 1 }); + buttons.at(2).simulate('click'); + expect(p.text()).toMatch(/^2$/); + }); + }); +}); diff --git a/test/e2e/HomePage.e2e.ts b/test/e2e/HomePage.e2e.ts new file mode 100644 index 00000000..4ea4edd9 --- /dev/null +++ b/test/e2e/HomePage.e2e.ts @@ -0,0 +1,97 @@ +/* eslint jest/expect-expect: off, jest/no-test-callback: off */ +import { ClientFunction, Selector } from 'testcafe'; +import { getPageUrl } from './helpers'; + +const getPageTitle = ClientFunction(() => document.title); +const counterSelector = Selector('[data-tid="counter"]'); +const buttonsSelector = Selector('[data-tclass="btn"]'); +const clickToCounterLink = t => + t.click(Selector('a').withExactText('to Counter')); +const incrementButton = buttonsSelector.nth(0); +const decrementButton = buttonsSelector.nth(1); +const oddButton = buttonsSelector.nth(2); +const asyncButton = buttonsSelector.nth(3); +const getCounterText = () => counterSelector().innerText; +const assertNoConsoleErrors = async t => { + const { error } = await t.getBrowserConsoleMessages(); + await t.expect(error).eql([]); +}; + +fixture`Home Page`.page('../../app/app.html').afterEach(assertNoConsoleErrors); + +test('e2e', async t => { + await t.expect(getPageTitle()).eql('Hello Electron React!'); +}); + +test('should open window and contain expected page title', async t => { + await t.expect(getPageTitle()).eql('Hello Electron React!'); +}); + +test( + 'should not have any logs in console of main window', + assertNoConsoleErrors +); + +test('should navigate to Counter with click on the "to Counter" link', async t => { + await t + .click('[data-tid=container] > a') + .expect(getCounterText()) + .eql('0'); +}); + +test('should navigate to /counter', async t => { + await t + .click('a') + .expect(getPageUrl()) + .contains('/counter'); +}); + +fixture`Counter Tests` + .page('../../app/app.html') + .beforeEach(clickToCounterLink) + .afterEach(assertNoConsoleErrors); + +test('should display updated count after the increment button click', async t => { + await t + .click(incrementButton) + .expect(getCounterText()) + .eql('1'); +}); + +test('should display updated count after the descrement button click', async t => { + await t + .click(decrementButton) + .expect(getCounterText()) + .eql('-1'); +}); + +test('should not change even counter if odd button clicked', async t => { + await t + .click(oddButton) + .expect(getCounterText()) + .eql('0'); +}); + +test('should change odd counter if odd button clicked', async t => { + await t + .click(incrementButton) + .click(oddButton) + .expect(getCounterText()) + .eql('2'); +}); + +test('should change if async button clicked and a second later', async t => { + await t + .click(asyncButton) + .expect(getCounterText()) + .eql('0') + .expect(getCounterText()) + .eql('1'); +}); + +test('should back to home if back button clicked', async t => { + await t + .click('[data-tid="backButton"] > a') + .expect(Selector('[data-tid="container"]').visible) + .ok(); +}); diff --git a/test/e2e/helpers.ts b/test/e2e/helpers.ts new file mode 100644 index 00000000..017a3445 --- /dev/null +++ b/test/e2e/helpers.ts @@ -0,0 +1,4 @@ +/* eslint import/prefer-default-export: off */ +import { ClientFunction } from 'testcafe'; + +export const getPageUrl = ClientFunction(() => window.location.href); diff --git a/test/reducers/__snapshots__/counter.spec.ts.snap b/test/reducers/__snapshots__/counter.spec.ts.snap new file mode 100644 index 00000000..9d78460b --- /dev/null +++ b/test/reducers/__snapshots__/counter.spec.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`reducers counter should handle DECREMENT_COUNTER 1`] = `0`; + +exports[`reducers counter should handle INCREMENT_COUNTER 1`] = `2`; + +exports[`reducers counter should handle initial state 1`] = `0`; + +exports[`reducers counter should handle unknown action type 1`] = `1`; diff --git a/test/reducers/counter.spec.ts b/test/reducers/counter.spec.ts new file mode 100644 index 00000000..f111c17a --- /dev/null +++ b/test/reducers/counter.spec.ts @@ -0,0 +1,25 @@ +import counter from '../../app/reducers/counter'; +import { + INCREMENT_COUNTER, + DECREMENT_COUNTER +} from '../../app/actions/counter'; + +describe('reducers', () => { + describe('counter', () => { + it('should handle initial state', () => { + expect(counter(undefined, {})).toMatchSnapshot(); + }); + + it('should handle INCREMENT_COUNTER', () => { + expect(counter(1, { type: INCREMENT_COUNTER })).toMatchSnapshot(); + }); + + it('should handle DECREMENT_COUNTER', () => { + expect(counter(1, { type: DECREMENT_COUNTER })).toMatchSnapshot(); + }); + + it('should handle unknown action type', () => { + expect(counter(1, { type: 'unknown' })).toMatchSnapshot(); + }); + }); +});