mirror of https://github.com/lukechilds/polar.git
jamaljsr
5 years ago
committed by
jamaljsr
18 changed files with 12 additions and 399 deletions
@ -1,64 +0,0 @@ |
|||
import { Counter, Home } from './pages'; |
|||
import { assertNoConsoleErrors, pageUrl, getPageUrl } from './helpers'; |
|||
|
|||
fixture`Counter` |
|||
.page(pageUrl) |
|||
.beforeEach(Home.clickCounterLink) |
|||
.afterEach(assertNoConsoleErrors); |
|||
|
|||
test('should be on the route /counter', async t => { |
|||
await t.expect(getPageUrl()).match(/.*#\/counter$/); |
|||
}); |
|||
|
|||
test('should display updated count after increment button click', async t => { |
|||
await t |
|||
.click(Counter.increment) |
|||
.expect(Counter.getCounterText()) |
|||
.eql('1'); |
|||
}); |
|||
|
|||
test('should display updated count after decrement button click', async t => { |
|||
await t |
|||
.click(Counter.decrement) |
|||
.expect(Counter.getCounterText()) |
|||
.eql('-1'); |
|||
}); |
|||
|
|||
test('should not change when count is even and odd button clicked', async t => { |
|||
await t |
|||
.click(Counter.incrementOdd) |
|||
.expect(Counter.getCounterText()) |
|||
.eql('0'); |
|||
}); |
|||
|
|||
test('should change when count is odd and odd button clicked', async t => { |
|||
await t |
|||
.click(Counter.increment) |
|||
.click(Counter.incrementOdd) |
|||
.expect(Counter.getCounterText()) |
|||
.eql('3'); |
|||
}); |
|||
|
|||
test('should change a second later if async button clicked', async t => { |
|||
await t |
|||
.click(Counter.incrementAsync) |
|||
.expect(Counter.loadingIcon) |
|||
.ok() |
|||
.expect(Counter.getCounterText()) |
|||
.eql('1'); |
|||
}); |
|||
|
|||
test('should show error if count is 3 and async button clicked', async t => { |
|||
await t |
|||
.click(Counter.increment) // increment to 1
|
|||
.click(Counter.incrementOdd) // increment to 3
|
|||
.click(Counter.incrementAsync) |
|||
.expect(Counter.loadingIcon.exists) |
|||
.ok() |
|||
.expect(Counter.getCounterText()) |
|||
.eql('3') |
|||
.expect(Counter.error.exists) |
|||
.ok() |
|||
.expect(Counter.getErrorText()) |
|||
.eql('Increment Async prohibited when count is 3.'); |
|||
}); |
@ -1,16 +0,0 @@ |
|||
import { Selector } from 'testcafe'; |
|||
|
|||
class Counter { |
|||
counter: Selector = Selector('[data-tid=counter]'); |
|||
increment: Selector = Selector('[data-tid=incr-btn]'); |
|||
decrement: Selector = Selector('[data-tid=decr-btn]'); |
|||
incrementOdd: Selector = Selector('[data-tid=odd-btn]'); |
|||
incrementAsync: Selector = Selector('[data-tid=async-btn]'); |
|||
loadingIcon: Selector = Selector('[data-tid=async-loader]'); |
|||
error: Selector = Selector('[data-tid=error]'); |
|||
|
|||
getCounterText = () => this.counter.innerText; |
|||
getErrorText = () => this.error.innerText; |
|||
} |
|||
|
|||
export default new Counter(); |
@ -1,4 +1,3 @@ |
|||
export { default as App } from './App'; |
|||
export { default as Home } from './Home'; |
|||
export { default as Counter } from './Counter'; |
|||
export { default as NewNetwork } from './NewNetwork'; |
|||
|
@ -1,12 +0,0 @@ |
|||
.body { |
|||
padding: 20px; |
|||
text-align: center; |
|||
|
|||
.counter { |
|||
font-size: 5rem; |
|||
} |
|||
|
|||
.btnGroup .btn { |
|||
margin: 5px; |
|||
} |
|||
} |
@ -1,96 +0,0 @@ |
|||
import React from 'react'; |
|||
import { |
|||
fireEvent, |
|||
waitForElement, |
|||
waitForElementToBeRemoved, |
|||
} from '@testing-library/react'; |
|||
|
|||
import { renderWithProviders } from 'utils/tests'; |
|||
import Counter from './Counter'; |
|||
|
|||
describe('Counter component', () => { |
|||
const renderComponent = () => { |
|||
return renderWithProviders(<Counter />); |
|||
}; |
|||
|
|||
it('should contain default counter value of zero', () => { |
|||
const { getByTestId } = renderComponent(); |
|||
expect(getByTestId('counter')).toHaveTextContent('0'); |
|||
}); |
|||
|
|||
it('should increment by one when plus btn is clicked', () => { |
|||
const { getByTestId } = renderComponent(); |
|||
const btn = getByTestId('incr-btn'); |
|||
fireEvent.click(btn); |
|||
expect(getByTestId('counter')).toHaveTextContent('1'); |
|||
}); |
|||
|
|||
it('should decrement by one when minus btn is clicked', () => { |
|||
const { getByTestId } = renderComponent(); |
|||
const btn = getByTestId('decr-btn'); |
|||
fireEvent.click(btn); |
|||
expect(getByTestId('counter')).toHaveTextContent('-1'); |
|||
}); |
|||
|
|||
it('should not increment when odd btn is clicked and count is even', () => { |
|||
const { getByTestId } = renderComponent(); |
|||
const btn = getByTestId('odd-btn'); |
|||
fireEvent.click(btn); |
|||
expect(getByTestId('counter')).toHaveTextContent('0'); |
|||
}); |
|||
|
|||
it('should increment by two when odd btn is clicked and count is odd', () => { |
|||
const { getByTestId } = renderComponent(); |
|||
|
|||
// first increment to 1 so that the current count is odd
|
|||
const incr = getByTestId('incr-btn'); |
|||
fireEvent.click(incr); |
|||
|
|||
const btn = getByTestId('odd-btn'); |
|||
fireEvent.click(btn); |
|||
expect(getByTestId('counter')).toHaveTextContent('3'); |
|||
}); |
|||
|
|||
it('should show loader when async btn is clicked', async () => { |
|||
const { getByTestId } = renderComponent(); |
|||
const btn = getByTestId('async-btn'); |
|||
fireEvent.click(btn); |
|||
const loader = await waitForElement(() => getByTestId('async-loader')); |
|||
expect(loader).not.toBeNull(); |
|||
}); |
|||
|
|||
it('should increment after some time when async btn is clicked', async () => { |
|||
const { getByTestId } = renderComponent(); |
|||
const btn = getByTestId('async-btn'); |
|||
fireEvent.click(btn); |
|||
|
|||
// wait for loader to show and then be removed
|
|||
await waitForElement(() => getByTestId('async-loader')); |
|||
await waitForElementToBeRemoved(() => getByTestId('async-loader')); |
|||
|
|||
expect(btn).toHaveTextContent('cmps.counter.increment-async'); |
|||
expect(getByTestId('counter')).toHaveTextContent('1'); |
|||
}); |
|||
|
|||
it('should raise error when count is 3 and async btn is clicked', async () => { |
|||
const { getByTestId } = renderComponent(); |
|||
|
|||
// first increment to 3
|
|||
const incr = getByTestId('incr-btn'); |
|||
fireEvent.click(incr); |
|||
fireEvent.click(incr); |
|||
fireEvent.click(incr); |
|||
|
|||
const btn = getByTestId('async-btn'); |
|||
fireEvent.click(btn); |
|||
|
|||
// wait for loader to show and then be removed
|
|||
await waitForElement(() => getByTestId('async-loader')); |
|||
await waitForElementToBeRemoved(() => getByTestId('async-loader')); |
|||
|
|||
expect(btn).toHaveTextContent('cmps.counter.increment-async'); |
|||
expect(getByTestId('error')).toHaveTextContent( |
|||
'models.counter.increment-async.error', |
|||
); |
|||
}); |
|||
}); |
@ -1,74 +0,0 @@ |
|||
import React, { useEffect } from 'react'; |
|||
import { Alert, Button, Icon } from 'antd'; |
|||
import { useStoreState, useStoreActions } from 'store'; |
|||
import { useAsyncCallback } from 'react-async-hook'; |
|||
import { useTranslation } from 'react-i18next'; |
|||
import styles from './Counter.module.less'; |
|||
import { info } from 'electron-log'; |
|||
|
|||
const Counter = () => { |
|||
useEffect(() => info('Rendering Counter component'), []); |
|||
const { t } = useTranslation(); |
|||
const { count } = useStoreState(s => s.counter); |
|||
const { increment, decrement, incrementIfOdd, incrementAsync } = useStoreActions( |
|||
a => a.counter, |
|||
); |
|||
const { execute: incrementAsyncCb, loading, error } = useAsyncCallback(() => |
|||
incrementAsync(), |
|||
); |
|||
const [incrementCb, decrementCb, incrementIfOddCb] = [ |
|||
increment, |
|||
decrement, |
|||
incrementIfOdd, |
|||
].map(x => () => x()); |
|||
|
|||
return ( |
|||
<div className={styles.body}> |
|||
{error && <Alert message={error.message} type="error" data-tid="error" />} |
|||
<h1 className={styles.counter} data-tid="counter"> |
|||
{loading ? <Icon type="loading" data-tid="async-loader" /> : count} |
|||
</h1> |
|||
<div className={styles.btnGroup}> |
|||
<Button |
|||
type="primary" |
|||
icon="plus" |
|||
className={styles.btn} |
|||
data-tid="incr-btn" |
|||
onClick={incrementCb} |
|||
> |
|||
{t('cmps.counter.increment', 'Increment')} |
|||
</Button> |
|||
<Button |
|||
type="primary" |
|||
icon="minus" |
|||
className={styles.btn} |
|||
data-tid="decr-btn" |
|||
onClick={decrementCb} |
|||
> |
|||
{t('cmps.counter.decrement', 'Decrement')} |
|||
</Button> |
|||
<Button |
|||
type="primary" |
|||
icon="question" |
|||
className={styles.btn} |
|||
data-tid="odd-btn" |
|||
onClick={incrementIfOddCb} |
|||
> |
|||
{t('cmps.counter.increment-odd', 'Increment Odd')} |
|||
</Button> |
|||
<Button |
|||
type="primary" |
|||
icon="retweet" |
|||
className={styles.btn} |
|||
data-tid="async-btn" |
|||
onClick={incrementAsyncCb} |
|||
loading={loading} |
|||
> |
|||
{t('cmps.counter.increment-async', 'Increment Async')} |
|||
</Button> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default Counter; |
@ -1 +0,0 @@ |
|||
export { default as Counter } from './Counter'; |
@ -1,54 +0,0 @@ |
|||
import counterModel from './counter'; |
|||
import { createStore } from 'easy-peasy'; |
|||
|
|||
describe('counter model', () => { |
|||
// initialize store for type inference
|
|||
let store = createStore(counterModel); |
|||
|
|||
beforeEach(() => { |
|||
// reset the store before each test run
|
|||
store = createStore(counterModel); |
|||
}); |
|||
|
|||
it('should have a valid initial state', () => { |
|||
expect(store.getState().count).toBe(0); |
|||
}); |
|||
|
|||
it('should increment by one', () => { |
|||
store.getActions().increment(); |
|||
expect(store.getState().count).toBe(1); |
|||
}); |
|||
|
|||
it('should decrement by one', () => { |
|||
store.getActions().decrement(); |
|||
expect(store.getState().count).toBe(-1); |
|||
}); |
|||
|
|||
it('should increment by two if count is odd', () => { |
|||
// initialize state with an odd number
|
|||
store = createStore(counterModel, { initialState: { count: 1 } }); |
|||
store.getActions().incrementIfOdd(); |
|||
expect(store.getState().count).toBe(3); |
|||
}); |
|||
|
|||
it('should not increment by two if count is even', () => { |
|||
store.getActions().incrementIfOdd(); |
|||
expect(store.getState().count).toBe(0); |
|||
}); |
|||
|
|||
it('should increment after a delay', async () => { |
|||
await store.getActions().incrementAsync(); |
|||
expect(store.getState().count).toBe(1); |
|||
}); |
|||
|
|||
it('should fail to increment after a delay if count is three', async () => { |
|||
expect.assertions(1); |
|||
try { |
|||
// initialize state with count set to three
|
|||
store = createStore(counterModel, { initialState: { count: 3 } }); |
|||
await store.getActions().incrementAsync(); |
|||
} catch (e) { |
|||
expect(e.message).toMatch('models.counter.increment-async.error'); |
|||
} |
|||
}); |
|||
}); |
@ -1,48 +0,0 @@ |
|||
import { Action, action, Thunk, thunk } from 'easy-peasy'; |
|||
import i18n from 'i18next'; |
|||
import { info } from 'electron-log'; |
|||
|
|||
export interface CounterModel { |
|||
count: number; |
|||
increment: Action<CounterModel>; |
|||
decrement: Action<CounterModel>; |
|||
incrementIfOdd: Action<CounterModel>; |
|||
incrementAsync: Thunk<CounterModel, number | void>; |
|||
} |
|||
|
|||
const counterModel: CounterModel = { |
|||
// state vars
|
|||
count: 0, |
|||
// reducer actions (mutations allowed thx to immer)
|
|||
increment: action(state => { |
|||
state.count++; |
|||
info(`Incremented count in redux state to ${state.count}`); |
|||
}), |
|||
decrement: action(state => { |
|||
state.count = state.count - 1; |
|||
info(`Decremented count in redux state to ${state.count}`); |
|||
}), |
|||
incrementIfOdd: action(state => { |
|||
info(`Incrementing count in redux state by 2 if "${state.count}" is odd`); |
|||
if (state.count % 2 !== 0) { |
|||
state.count += 2; |
|||
info(`Incremented count in redux state to ${state.count}`); |
|||
} |
|||
}), |
|||
incrementAsync: thunk(async (actions, payload, { getState }) => { |
|||
info(`Incremented count in redux state asynchronously`); |
|||
return new Promise((resolve, reject) => { |
|||
setTimeout(() => { |
|||
if (getState().count !== 3) { |
|||
actions.increment(); |
|||
resolve(); |
|||
} else { |
|||
info(`Failed to increment count because it is currently ${getState().count}`); |
|||
reject(new Error(i18n.t('models.counter.increment-async.error'))); |
|||
} |
|||
}, payload || 1000); |
|||
}); |
|||
}), |
|||
}; |
|||
|
|||
export default counterModel; |
Loading…
Reference in new issue