Browse Source

Update test-e2e

master
Arnaud97234 7 years ago
parent
commit
ccbc22d35a
No known key found for this signature in database GPG Key ID: C77229DB9ECCFE6
  1. 4
      .circleci/config.yml
  2. 2
      src/components/DashboardPage/AccountCard/index.js
  3. 1
      src/components/DashboardPage/AccountCardList.js
  4. 2
      src/components/DashboardPage/AccountCardListHeader.js
  5. 2
      src/components/DashboardPage/AccountCardPlaceholder.js
  6. 2
      src/components/DashboardPage/CurrentGreetings.js
  7. 7
      src/components/DashboardPage/SummaryDesc.js
  8. 2
      src/components/MainSideBar/AddAccountButton.js
  9. 14
      src/components/Onboarding/steps/Analytics.js
  10. 2
      src/components/OperationsList/index.js
  11. 1
      src/components/SelectCurrency/index.js
  12. 4
      src/components/SettingsPage/DisablePasswordModal.js
  13. 6
      src/components/SettingsPage/PasswordButton.js
  14. 2
      src/components/SettingsPage/PasswordForm.js
  15. 20
      src/components/SettingsPage/PasswordModal.js
  16. 2
      src/components/SettingsPage/SentryLogsButton.js
  17. 2
      src/components/SettingsPage/SettingsSection.js
  18. 6
      src/components/SettingsPage/ShareAnalyticsButton.js
  19. 1
      src/components/TopBar/ActivityIndicator.js
  20. 1
      src/components/base/InputCurrency/index.js
  21. 2
      src/components/base/Modal/ModalTitle.js
  22. 2
      src/components/modals/Disclaimer.js
  23. 6
      src/components/modals/ShareAnalytics.js
  24. 4
      src/components/modals/TechnicalData.js
  25. 40
      test-e2e/helpers/test_helpers.js
  26. 64
      test-e2e/nav_to_settings.spec.js
  27. 119
      test-e2e/skipOnboarding_GeneralSettingsCheck.spec.js

4
.circleci/config.yml

@ -13,10 +13,10 @@ jobs:
- checkout
- restore_cache:
keys:
- v8-yarn-packages-{{ checksum "yarn.lock" }}
- v10-yarn-packages-{{ checksum "yarn.lock" }}
- run: yarn install
- save_cache:
key: v8-yarn-packages-{{ checksum "yarn.lock" }}
key: v10-yarn-packages-{{ checksum "yarn.lock" }}
paths:
- node_modules
- run: yarn lint

2
src/components/DashboardPage/AccountCard/index.js

@ -69,7 +69,7 @@ class AccountCard extends PureComponent<{
render() {
const { counterValue, account, onClick, daysCount, ...props } = this.props
return (
<Wrapper onClick={this.onClick} {...props}>
<Wrapper onClick={this.onClick} {...props} data-e2e="dashboard_AccountCardWrapper">
<Box flow={4}>
<AccountCardHeader accountName={account.name} currency={account.currency} />
<Bar size={1} color="fog" />

1
src/components/DashboardPage/AccountCardList.js

@ -28,6 +28,7 @@ class AccountCardList extends Component<Props> {
justifyContent="flex-start"
alignItems="center"
style={{ margin: '0 -16px' }}
data-e2e="dashboard_AccountList"
>
{accounts
.map(account => ({

2
src/components/DashboardPage/AccountCardListHeader.js

@ -19,7 +19,7 @@ class AccountCardListHeader extends PureComponent<Props> {
return (
<Box horizontal alignItems="flex-end">
<Text color="dark" ff="Museo Sans" fontSize={6}>
<Text color="dark" ff="Museo Sans" fontSize={6} data-e2e="dashboard_AccountCount">
{t('app:dashboard.accounts.title', { count: accountsLength })}
</Text>
<Box ml="auto" horizontal flow={1}>

2
src/components/DashboardPage/AccountCardPlaceholder.js

@ -31,7 +31,7 @@ class AccountCardPlaceholder extends PureComponent<{
render() {
const { t } = this.props
return (
<Wrapper>
<Wrapper data-e2e="dashboard_AccountPlaceOrder">
<Box mt={2}>
<img alt="" src={i('empty-account-tile.svg')} />
</Box>

2
src/components/DashboardPage/CurrentGreetings.js

@ -21,7 +21,7 @@ class CurrentGettings extends PureComponent<{ t: T }> {
render() {
const { t } = this.props
return (
<Text color="dark" ff="Museo Sans" fontSize={7}>
<Text color="dark" ff="Museo Sans" fontSize={7} data-e2e="dashboard_currentGettings">
{t(getCurrentGreetings())}
</Text>
)

7
src/components/DashboardPage/SummaryDesc.js

@ -12,7 +12,12 @@ class SummaryDesc extends PureComponent<{
render() {
const { totalAccounts, t } = this.props
return (
<Text color="grey" fontSize={5} ff="Museo Sans|Light">
<Text
color="grey"
fontSize={5}
ff="Museo Sans|Light"
data-e2e="dashboard_accountsSummaryDesc"
>
{t('app:dashboard.summary', { count: totalAccounts })}
</Text>
)

2
src/components/MainSideBar/AddAccountButton.js

@ -33,7 +33,7 @@ export default class AddAccountButton extends PureComponent<{
return (
<Tooltip render={() => tooltipText}>
<PlusWrapper onClick={onClick}>
<IconCirclePlus size={16} />
<IconCirclePlus size={16} data-e2e="menuAddAccount_button" />
</PlusWrapper>
</Tooltip>
)

14
src/components/Onboarding/steps/Analytics.js

@ -76,7 +76,9 @@ class Analytics extends PureComponent<StepProps, State> {
<Container>
<Box>
<Box horizontal mb={1}>
<AnalyticsTitle>{t('onboarding:analytics.technicalData.title')}</AnalyticsTitle>
<AnalyticsTitle data-e2e="analytics_techData">
{t('onboarding:analytics.technicalData.title')}
</AnalyticsTitle>
<LearnMoreWrapper>
<FakeLink
underline
@ -84,6 +86,7 @@ class Analytics extends PureComponent<StepProps, State> {
color="smoke"
ml={2}
onClick={this.handleTechnicalDataModal}
data-e2e="analytics_techData_Link"
>
{t('app:common.learnMore')}
</FakeLink>
@ -102,7 +105,9 @@ class Analytics extends PureComponent<StepProps, State> {
<Container>
<Box>
<Box horizontal mb={1}>
<AnalyticsTitle>{t('onboarding:analytics.shareAnalytics.title')}</AnalyticsTitle>
<AnalyticsTitle data-e2e="analytics_shareAnalytics">
{t('onboarding:analytics.shareAnalytics.title')}
</AnalyticsTitle>
<LearnMoreWrapper>
<FakeLink
style={{ textDecoration: 'underline' }}
@ -110,6 +115,7 @@ class Analytics extends PureComponent<StepProps, State> {
color="smoke"
ml={2}
onClick={this.handleShareAnalyticsModal}
data-e2e="analytics_shareAnalytics_Link"
>
{t('app:common.learnMore')}
</FakeLink>
@ -133,7 +139,9 @@ class Analytics extends PureComponent<StepProps, State> {
<Container>
<Box>
<Box mb={1}>
<AnalyticsTitle>{t('onboarding:analytics.sentryLogs.title')}</AnalyticsTitle>
<AnalyticsTitle data-e2e="analytics_reportBugs">
{t('onboarding:analytics.sentryLogs.title')}
</AnalyticsTitle>
</Box>
<AnalyticsText>{t('onboarding:analytics.sentryLogs.desc')}</AnalyticsText>
</Box>

2
src/components/OperationsList/index.js

@ -102,7 +102,7 @@ export class OperationsList extends PureComponent<Props, State> {
return (
<Box flow={4}>
{title && (
<Text color="dark" ff="Museo Sans" fontSize={6}>
<Text color="dark" ff="Museo Sans" fontSize={6} data-e2e="dashboard_OperationList">
{title}
</Text>
)}

1
src/components/SelectCurrency/index.js

@ -40,6 +40,7 @@ const SelectCurrency = ({ onChange, value, t, placeholder, currencies, ...props
renderValue={renderOption}
options={options}
placeholder={placeholder || t('app:common.selectCurrency')}
data-e2e="test"
noOptionsMessage={({ inputValue }: { inputValue: string }) =>
t('app:common.selectCurrencyNoOption', { currencyName: inputValue })
}

4
src/components/SettingsPage/DisablePasswordModal.js

@ -68,7 +68,9 @@ class DisablePasswordModal extends PureComponent<Props, State> {
render={({ onClose }) => (
<form onSubmit={this.disablePassword}>
<ModalBody onClose={onClose}>
<ModalTitle>{t('app:password.disablePassword.title')}</ModalTitle>
<ModalTitle data-e2e="disablePassword_modalTitle">
{t('app:password.disablePassword.title')}
</ModalTitle>
<ModalContent>
<Box ff="Open Sans" color="smoke" fontSize={4} textAlign="center" px={4}>
{t('app:password.disablePassword.desc')}

6
src/components/SettingsPage/PasswordButton.js

@ -88,7 +88,11 @@ class PasswordButton extends PureComponent<Props, State> {
{t('app:settings.profile.changePassword')}
</Button>
)}
<Switch isChecked={hasPassword} onChange={this.handleChangePasswordCheck} />
<Switch
isChecked={hasPassword}
onChange={this.handleChangePasswordCheck}
data-e2e="passwordLock_button"
/>
</Box>
<PasswordModal

2
src/components/SettingsPage/PasswordForm.js

@ -61,6 +61,7 @@ class PasswordForm extends PureComponent<Props> {
id="newPassword"
onChange={onChange('newPassword')}
value={newPassword}
data-e2e="setPassword_NewPassword"
/>
</Box>
<Box flow={1}>
@ -73,6 +74,7 @@ class PasswordForm extends PureComponent<Props> {
onChange={onChange('confirmPassword')}
value={confirmPassword}
error={!isValid() && confirmPassword.length > 0 && new PasswordsDontMatchError()}
data-e2e="setPassword_ConfirmPassword"
/>
</Box>
<button hidden type="submit" />

20
src/components/SettingsPage/PasswordModal.js

@ -85,10 +85,19 @@ class PasswordModal extends PureComponent<Props, State> {
{hasPassword ? (
<ModalTitle>{t('app:password.changePassword.title')}</ModalTitle>
) : (
<ModalTitle>{t('app:password.setPassword.title')}</ModalTitle>
<ModalTitle data-e2e="enablePassword_modal">
{t('app:password.setPassword.title')}
</ModalTitle>
)}
<ModalContent>
<Box ff="Museo Sans|Regular" color="dark" textAlign="center" mb={2} mt={3}>
<Box
ff="Museo Sans|Regular"
color="dark"
textAlign="center"
mb={2}
mt={3}
data-e2e="setPassword_modalTitle"
>
{hasPassword
? t('app:password.changePassword.subTitle')
: t('app:password.setPassword.subTitle')}
@ -109,7 +118,12 @@ class PasswordModal extends PureComponent<Props, State> {
/>
</ModalContent>
<ModalFooter horizontal align="center" justify="flex-end" flow={2}>
<Button small type="button" onClick={onClose}>
<Button
small
type="button"
onClick={onClose}
data-e2e="setPassword_modalCancel_button"
>
{t('app:common.cancel')}
</Button>
<Button

2
src/components/SettingsPage/SentryLogsButton.js

@ -27,7 +27,7 @@ class SentryLogsButton extends PureComponent<Props> {
return (
<Fragment>
<Track onUpdate event={sentryLogs ? 'SentryEnabled' : 'SentryDisabled'} />
<Switch isChecked={sentryLogs} onChange={setSentryLogs} />
<Switch isChecked={sentryLogs} onChange={setSentryLogs} data-e2e="reportBugs_button" />
</Fragment>
)
}

2
src/components/SettingsPage/SettingsSection.js

@ -59,7 +59,7 @@ export function SettingsSectionHeader({
<SettingsSectionHeaderContainer tabIndex={-1}>
<RoundIconContainer mr={3}>{icon}</RoundIconContainer>
<Box grow>
<Box ff="Museo Sans|Regular" color="dark">
<Box ff="Museo Sans|Regular" color="dark" data-e2e="settingsGeneral_title">
{title}
</Box>
<Box ff="Open Sans" fontSize={3} mt={1}>

6
src/components/SettingsPage/ShareAnalyticsButton.js

@ -26,7 +26,11 @@ class ShareAnalytics extends PureComponent<Props> {
return (
<Fragment>
<Track onUpdate event={shareAnalytics ? 'AnalyticsEnabled' : 'AnalyticsDisabled'} />
<Switch isChecked={shareAnalytics} onChange={setShareAnalytics} />
<Switch
isChecked={shareAnalytics}
onChange={setShareAnalytics}
data-e2e="shareAnalytics_button"
/>
</Fragment>
)
}

1
src/components/TopBar/ActivityIndicator.js

@ -76,6 +76,7 @@ class ActivityIndicatorInner extends PureComponent<Props, { lastClickTime: numbe
)}
</Rotating>
<Box
data-e2e="syncButton"
ml={isRotating ? 2 : 1}
ff="Open Sans|SemiBold"
color={isError ? 'alertRed' : undefined}

1
src/components/base/InputCurrency/index.js

@ -209,6 +209,7 @@ class InputCurrency extends PureComponent<Props, State> {
return (
<Input
data-e2e="addAccount_currencyInput"
{...this.props}
ff="Rubik"
ref={this.onRef}

2
src/components/base/Modal/ModalTitle.js

@ -60,7 +60,7 @@ function ModalTitle({
children: any,
}) {
return (
<Container {...props}>
<Container {...props} data-e2e="modal_title">
{onBack && (
<Back onClick={onBack}>
<IconAngleLeft size={16} />

2
src/components/modals/Disclaimer.js

@ -25,7 +25,7 @@ class DisclaimerModal extends PureComponent<Props> {
name={MODAL_DISCLAIMER}
render={({ onClose }) => (
<ModalBody onClose={onClose}>
<ModalTitle data-e2e="disclaimer_title">{t('app:disclaimerModal.title')}</ModalTitle>
<ModalTitle>{t('app:disclaimerModal.title')}</ModalTitle>
<ModalContent flow={4} ff="Open Sans|Regular" fontSize={4} color="smoke">
<Box align="center" mt={4} pb={4}>
<HandShield size={55} />

6
src/components/modals/ShareAnalytics.js

@ -64,13 +64,15 @@ class ShareAnalytics extends PureComponent<Props, *> {
name={MODAL_SHARE_ANALYTICS}
render={({ onClose }) => (
<ModalBody onClose={onClose}>
<ModalTitle>{t('onboarding:analytics.shareAnalytics.title')}</ModalTitle>
<ModalTitle data-e2e="modal_title_shareAnalytics">
{t('onboarding:analytics.shareAnalytics.title')}
</ModalTitle>
<InlineDesc>{t('onboarding:analytics.shareAnalytics.desc')}</InlineDesc>
<ModalContent mx={5}>
<Ul>{items.map(item => <li key={item.key}>{item.desc}</li>)}</Ul>
</ModalContent>
<ModalFooter horizontal justifyContent="flex-end">
<Button onClick={onClose} primary>
<Button onClick={onClose} primary data-e2e="modal_buttonClose_shareAnalytics">
{t('app:common.close')}
</Button>
</ModalFooter>

4
src/components/modals/TechnicalData.js

@ -45,7 +45,7 @@ class TechnicalData extends PureComponent<Props, *> {
name={MODAL_TECHNICAL_DATA}
render={({ onClose }) => (
<ModalBody onClose={onClose}>
<ModalTitle>
<ModalTitle data-e2e="modal_title_TechData">
{t('onboarding:analytics.technicalData.mandatoryContextual.title')}
</ModalTitle>
<InlineDesc>{t('onboarding:analytics.technicalData.desc')}</InlineDesc>
@ -53,7 +53,7 @@ class TechnicalData extends PureComponent<Props, *> {
<Ul>{items.map(item => <li key={item.key}>{item.desc}</li>)}</Ul>
</ModalContent>
<ModalFooter horizontal justifyContent="flex-end">
<Button onClick={onClose} primary>
<Button onClick={onClose} primary data-e2e="modal_buttonClose_techData">
{t('app:common.close')}
</Button>
</ModalFooter>

40
test-e2e/helpers/test_helpers.js

@ -0,0 +1,40 @@
import { delay } from 'helpers/promise'
// Wait for an element to be present then continue
export function waitForExpectedText(app, selector, expected, maxRetry = 5) {
async function check() {
if (!maxRetry) {
throw new Error(`Cant find the element ${selector} in the page`)
}
try {
const str = await app.client.getText(selector)
if (str === expected) {
return true
}
} catch (err) {} // eslint-disable-line
await delay(500)
--maxRetry
return check()
}
return check()
}
// Wait for an element to disappear then continue
export function waitForDisappear(app, selector, maxRetry = 5) {
async function check() {
if (!maxRetry) {
throw new Error('Too many retries for waiting element to disappear')
}
try {
await app.client.getText(selector)
} catch (err) {
if (err.message.startsWith('An element could not be located')) {
return true
}
}
await delay(500)
--maxRetry
return check()
}
return check()
}

64
test-e2e/nav_to_settings.spec.js

@ -1,64 +0,0 @@
const Application = require('spectron').Application
let app
const TIMEOUT = 50 * 1000
describe('Application launch', () => {
beforeEach(async () => {
app = new Application({
path: './dist/ledger-live-desktop-1.1.0-linux-x86_64.AppImage',
env: {
SKIP_ONBOARDING: '1',
},
})
await app.start()
}, TIMEOUT)
afterEach(async () => {
if (app && app.isRunning()) {
await app.stop()
}
}, TIMEOUT)
test(
'Start app and set developper mode ',
async () => {
const title = await app.client.getTitle()
expect(title).toEqual('Ledger Live')
await app.client.waitUntilWindowLoaded()
await app.client.pause(2000)
// Post Onboarding
const title_onboarding = await app.client.getText('[data-e2e=onboarding_title]')
expect(title_onboarding).toEqual('Analytics and bug reports')
await app.client.click('[data-e2e=continue_button]')
await app.client.pause(1000)
const title_finish = await app.client.getText('[data-e2e=finish_title]')
expect(title_finish).toEqual('Your device is ready!')
await app.client.click('[data-e2e=continue_button]')
await app.client.pause(1000)
const title_disclaimer = await app.client.getText('[data-e2e=disclaimer_title]')
expect(title_disclaimer).toEqual('Trade safely')
await app.client.click('[data-e2e=continue_button]')
await app.client.pause(1000)
// Dashboard EmptyState
const title_dashboard_empty = await app.client.getText('[data-e2e=dashboard_empty_title]')
expect(title_dashboard_empty).toEqual('Add accounts to your portfolio')
// Open Settings
await app.client.click('[data-e2e=setting_button]')
await app.client.pause(1000)
const title_settings = await app.client.getText('[data-e2e=settings_title]')
expect(title_settings).toEqual('Settings')
// DevMode ON
await app.client.click('[data-e2e=devMode_button]')
await app.client.pause(500)
},
TIMEOUT,
)
})

119
test-e2e/skipOnboarding_GeneralSettingsCheck.spec.js

@ -0,0 +1,119 @@
import { Application } from 'spectron'
import { waitForDisappear, waitForExpectedText } from '../test-e2e/helpers/test_helpers'
const os = require('os')
const appVersion = require('../package.json')
let app
const TIMEOUT = 50 * 1000
let app_path
const platform = os.platform()
if (platform === 'darwin') {
app_path = `./dist/mac/Ledger Live.app/Contents/MacOS/Ledger Live`
} else if (platform === 'win32') {
app_path = `./dist\\win-unpacked\\Ledger Live.exe`
} else {
app_path = `./dist/ledger-live-desktop-${appVersion.version}-linux-x86_64.AppImage`
}
describe('Application launch', () => {
beforeEach(async () => {
app = new Application({
path: app_path,
env: {
SKIP_ONBOARDING: '1',
},
})
await app.start()
}, TIMEOUT)
afterEach(async () => {
if (app && app.isRunning()) {
await app.stop()
}
}, TIMEOUT)
test(
'Start app, skip onboarding, check Empty State, check General Settings and verify Developer mode',
async () => {
const title = await app.client.getTitle()
expect(title).toEqual('Ledger Live')
await app.client.waitUntilWindowLoaded()
await waitForDisappear(app, '#preload')
// Post Onboarding (Analytics)
const analytics_title = await waitForExpectedText(
app,
'[data-e2e=onboarding_title]',
'Analytics and bug reports',
)
// Verify "Technical Data" + Link "Learn more"
const analytics_techData_title = await app.client.getText('[data-e2e=analytics_techData]')
expect(analytics_techData_title).toEqual('Technical data *')
await app.client.click('[data-e2e=analytics_techData_Link]')
await waitForExpectedText(app, '[data-e2e=modal_title]', 'Technical data')
await app.client.click('[data-e2e=modal_buttonClose_techData]')
analytics_title
// Verify "Share analytics" + Link "Learn more"
const analytics_shareAnalytics_title = await app.client.getText(
'[data-e2e=analytics_shareAnalytics]',
)
expect(analytics_shareAnalytics_title).toEqual('Share analytics')
await app.client.click('[data-e2e=analytics_shareAnalytics_Link]')
await waitForExpectedText(app, '[data-e2e=modal_title]', 'Share analytics')
await app.client.click('[data-e2e=modal_buttonClose_shareAnalytics]')
analytics_title
// Verify "Report bugs"
const analytics_reportBugs_title = await app.client.getText('[data-e2e=analytics_reportBugs]')
expect(analytics_reportBugs_title).toEqual('Report bugs')
await app.client.click('[data-e2e=continue_button]')
// Finish Onboarding
await waitForExpectedText(app, '[data-e2e=finish_title]', 'Your device is ready!')
await app.client.click('[data-e2e=continue_button]')
await waitForExpectedText(app, '[data-e2e=modal_title]', 'Trade safely')
await app.client.click('[data-e2e=continue_button]')
// Dashboard EmptyState
await waitForExpectedText(
app,
'[data-e2e=dashboard_empty_title]',
'Add accounts to your portfolio',
)
const openManager_button = await app.client.getText('[data-e2e=dashboard_empty_OpenManager]')
expect(openManager_button).toEqual('Open Manager')
const addAccount_button = await app.client.getText('[data-e2e=dashboard_empty_AddAccounts]')
expect(addAccount_button).toEqual('Add accounts')
// Open Settings
await app.client.click('[data-e2e=setting_button]')
await waitForExpectedText(app, '[data-e2e=settings_title]', 'Settings')
// Verify settings General section
const settingsGeneral_title = await app.client.getText('[data-e2e=settingsGeneral_title]')
expect(settingsGeneral_title).toEqual('General')
// TO ADD : VERIFY PASSWORD LOCK VALUE = DISABLE ???
// Report bugs = OFF
await app.client.click('[data-e2e=reportBugs_button]')
// Analytics = ON
await app.client.click('[data-e2e=shareAnalytics_button]')
// DevMode = ON
await app.client.click('[data-e2e=devMode_button]')
// Verify Dev mode
// Add New Account
await app.client.click('[data-e2e=menuAddAccount_button]')
await waitForExpectedText(app, '[data-e2e=modal_title]', 'Add accounts')
},
TIMEOUT,
)
})
Loading…
Cancel
Save