TST: e2e tests for storage encryption

This commit is contained in:
Overtorment 2020-03-19 15:51:35 +00:00
parent 8df2a8d64b
commit b1e7378e02
7 changed files with 184 additions and 47 deletions

View File

@ -47,6 +47,7 @@ export default class PlausibleDeniability extends Component {
<BlueSpacing20 />
<BlueButton
testID="CreateFakeStorageButton"
icon={{
name: 'shield',
type: 'font-awesome',

View File

@ -304,7 +304,9 @@ export default class Selftest extends Component {
if (this.state.isOk) {
return (
<View style={{ alignItems: 'center' }}>
<BlueText h4>OK</BlueText>
<BlueText testID="SelfTestOk" h4>
OK
</BlueText>
</View>
);
} else {

View File

@ -66,7 +66,7 @@ const About = () => {
<BlueLoading />
) : (
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
<ScrollView>
<ScrollView testID="AboutScrollView">
<BlueCard>
<BlueTextCentered h4>BlueWallet is a free and open source Bitcoin wallet. Licensed MIT.</BlueTextCentered>
<BlueSpacing20 />
@ -130,7 +130,7 @@ const About = () => {
<BlueButton onPress={handleOnReleaseNotesPress} title="Release notes" />
<BlueSpacing20 />
<BlueButton onPress={handleOnSelfTestPress} title="Run self test" />
<BlueButton onPress={handleOnSelfTestPress} title="Run self test" testID="RunSelfTestButton" />
<BlueTextCentered />
<BlueTextCentered>
{getApplicationName()} ver {getVersion()} (build {getBuildNumber()})

View File

@ -181,7 +181,11 @@ export default class EncryptStorage extends Component {
disabled={!this.state.storageIsEncrypted}
onPress={() => this.props.navigation.navigate('PlausibleDeniability')}
>
<BlueListItem disabled={!this.state.storageIsEncrypted} title={loc.settings.plausible_deniability} />
<BlueListItem
disabled={!this.state.storageIsEncrypted}
title={loc.settings.plausible_deniability}
testID="PlausibleDeniabilityButton"
/>
</TouchableOpacity>
)}
</ScrollView>

View File

@ -70,7 +70,7 @@ const Settings = () => {
</BlueCard>
)}
<BlueListItem title={loc.settings.about} component={TouchableOpacity} onPress={() => navigate('About')} />
<BlueListItem title={loc.settings.about} component={TouchableOpacity} onPress={() => navigate('About')} testID="AboutButton" />
</ScrollView>
</SafeBlueArea>
);

View File

@ -2,46 +2,182 @@
describe('BlueWallet UI Tests', () => {
it('can launch', async () => {
await waitFor(element(by.id('WalletsList')))
.toBeVisible()
.withTimeout(4000);
await yo('WalletsList');
});
it('can encrypt storage', async () => {
await waitFor(element(by.id('WalletsList')))
.toBeVisible()
.withTimeout(4000);
await expect(element(by.id('SettingsButton'))).toBeVisible();
await element(by.id('SettingsButton')).tap(); // detox hanges here
it('selftest passes', async () => {
await yo('WalletsList');
// go to settings, press SelfTest and wait for OK
await element(by.id('SettingsButton')).tap();
await element(by.id('AboutButton')).tap();
await element(by.id('AboutScrollView')).swipe('up', 'fast', 1); // in case emu screen is small and it doesnt fit
await element(by.id('RunSelfTestButton')).tap();
await yo('SelfTestOk', 120 * 1000);
});
it('can encrypt storage, with plausible deniability', async () => {
await yo('WalletsList');
// lets create a wallet
await helperCreateWallet();
// go to settings
await expect(element(by.id('SettingsButton'))).toBeVisible();
await element(by.id('SettingsButton')).tap();
await expect(element(by.id('EncryptStorageButton'))).toBeVisible();
// now go to Security page where we will enable encryption
// go to Security page where we will enable encryption
await element(by.id('EncryptStorageButton')).tap();
await expect(element(by.id('EncyptedAndPasswordProtected'))).toBeVisible();
await expect(element(by.id('PlausibleDeniabilityButton'))).toBeNotVisible();
if (device.getPlatform() === 'ios') {
console.warn('Android only test skipped');
return;
}
// lets encrypt the storage.
// first, trying to mistype second password:
await element(by.type('android.widget.CompoundButton')).tap(); // thats a switch lol
await element(by.type('android.widget.EditText')).typeText('08902\n');
await element(by.type('android.widget.CompoundButton')).tap(); // thats a switch lol. lets tap it
await element(by.type('android.widget.EditText')).typeText('08902');
await element(by.text('OK')).tap();
await element(by.type('android.widget.EditText')).typeText('666\n');
await element(by.type('android.widget.EditText')).typeText('666');
await element(by.text('OK')).tap();
await expect(element(by.text('Passwords do not match'))).toBeVisible();
await element(by.text('OK')).tap();
// TODO: finish writing this test
// now, lets put correct passwords and encrypt the storage
await element(by.type('android.widget.CompoundButton')).tap(); // thats a switch lol
await element(by.type('android.widget.EditText')).typeText('qqq');
await element(by.text('OK')).tap();
await element(by.type('android.widget.EditText')).typeText('qqq');
await element(by.text('OK')).tap();
// relaunch app
await device.terminateApp();
await device.launchApp({ newInstance: true });
await sleep(2000);
await waitFor(element(by.text('OK')))
.toBeVisible()
.withTimeout(4000);
// trying to decrypt with wrong password
await expect(element(by.text('Your storage is encrypted. Password is required to decrypt it'))).toBeVisible();
await element(by.type('android.widget.EditText')).typeText('wrong');
await element(by.text('OK')).tap();
await expect(element(by.text('Wrong password, please try again.'))).toBeVisible();
// correct password
await element(by.type('android.widget.EditText')).typeText('qqq');
await element(by.text('OK')).tap();
await yo('WalletsList');
// previously created wallet should be visible
await expect(element(by.id('cr34t3d'))).toBeVisible();
// now lets enable plausible deniability feature
// go to settings -> security screen -> plausible deniability screen
await element(by.id('SettingsButton')).tap();
await expect(element(by.id('EncryptStorageButton'))).toBeVisible();
await element(by.id('EncryptStorageButton')).tap();
await expect(element(by.id('EncyptedAndPasswordProtected'))).toBeVisible();
await expect(element(by.id('PlausibleDeniabilityButton'))).toBeVisible();
await element(by.id('PlausibleDeniabilityButton')).tap();
// trying to enable plausible denability
await element(by.id('CreateFakeStorageButton')).tap();
await expect(element(by.text('Password for fake storage should not match password for your main storage'))).toBeVisible();
// trying MAIN password: should fail, obviously
await element(by.type('android.widget.EditText')).typeText('qqq');
await element(by.text('OK')).tap();
await expect(element(by.text('Password is currently in use. Please, try a different password.'))).toBeVisible();
await element(by.text('OK')).tap();
// trying new password, but will mistype
await element(by.id('CreateFakeStorageButton')).tap();
await element(by.type('android.widget.EditText')).typeText('passwordForFakeStorage');
await element(by.text('OK')).tap();
await expect(element(by.text('Retype password'))).toBeVisible();
await element(by.type('android.widget.EditText')).typeText('passwordForFakeStorageWithTypo'); // retyping with typo
await element(by.text('OK')).tap();
await expect(element(by.text('Passwords do not match, try again'))).toBeVisible();
await element(by.text('OK')).tap();
// trying new password
await element(by.id('CreateFakeStorageButton')).tap();
await element(by.type('android.widget.EditText')).typeText('passwordForFakeStorage');
await element(by.text('OK')).tap();
await expect(element(by.text('Retype password'))).toBeVisible();
await element(by.type('android.widget.EditText')).typeText('passwordForFakeStorage'); // retyping
await element(by.text('OK')).tap();
await expect(element(by.text('Success'))).toBeVisible();
await element(by.text('OK')).tap();
// created fake storage.
// creating a wallet inside this fake storage
await helperCreateWallet('fake_wallet');
// relaunch the app, unlock with fake password, expect to see fake wallet
// relaunch app
await device.terminateApp();
await device.launchApp({ newInstance: true });
await sleep(2000);
await waitFor(element(by.text('OK')))
.toBeVisible()
.withTimeout(4000);
//
await expect(element(by.text('Your storage is encrypted. Password is required to decrypt it'))).toBeVisible();
await element(by.type('android.widget.EditText')).typeText('qqq');
await element(by.text('OK')).tap();
await yo('WalletsList');
// previously created wallet IN MAIN STORAGE should be visible
await expect(element(by.id('cr34t3d'))).toBeVisible();
// relaunch app
await device.terminateApp();
await device.launchApp({ newInstance: true });
await sleep(3000);
//
await expect(element(by.text('Your storage is encrypted. Password is required to decrypt it'))).toBeVisible();
await element(by.type('android.widget.EditText')).typeText('passwordForFakeStorage');
await element(by.text('OK')).tap();
await yo('WalletsList');
// previously created wallet in FAKE storage should be visible
await expect(element(by.id('fake_wallet'))).toBeVisible();
});
it('can create wallet, reload app and it persists', async () => {
await waitFor(element(by.id('WalletsList')))
await yo('WalletsList');
await helperCreateWallet();
await device.terminateApp();
await device.launchApp({ newInstance: true });
await yo('WalletsList');
await expect(element(by.id('cr34t3d'))).toBeVisible();
});
});
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function yo(id, timeout = 10000) {
return waitFor(element(by.id(id)))
.toBeVisible()
.withTimeout(4000);
.withTimeout(timeout);
}
async function helperCreateWallet(walletName) {
await element(by.id('CreateAWallet')).tap();
await element(by.id('WalletNameInput')).typeText('cr34t3d\n');
await element(by.id('WalletNameInput')).typeText(walletName || 'cr34t3d');
await waitFor(element(by.id('ActivateBitcoinButton')))
.toBeVisible()
.withTimeout(5000);
@ -61,13 +197,5 @@ describe('BlueWallet UI Tests', () => {
.withTimeout(5000);
await element(by.id('PleasebackupOk')).tap();
await expect(element(by.id('WalletsList'))).toBeVisible();
await expect(element(by.id('cr34t3d'))).toBeVisible();
await device.terminateApp();
await device.launchApp({ newInstance: true });
await waitFor(element(by.id('WalletsList')))
.toBeVisible()
.withTimeout(10000);
await expect(element(by.id('cr34t3d'))).toBeVisible();
});
});
await expect(element(by.id(walletName || 'cr34t3d'))).toBeVisible();
}

View File

@ -17,13 +17,15 @@ jasmine.getEnv().addReporter(specReporter);
jasmine.getEnv().addReporter(assignReporter);
// Set the default timeout
jest.setTimeout(90000);
jest.setTimeout(180000);
beforeAll(async () => {
await detox.init(config, { launchApp: false });
}, 300000);
beforeEach(async () => {
await device.uninstallApp();
await device.installApp();
await device.launchApp({ newInstance: true });
await sleep(2000);
await adapter.beforeEach();