Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the capability to change the language between tests #873

Merged
merged 38 commits into from
Sep 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
797a3dd
pipe language through to xcrun launch
Jul 20, 2018
bdff879
Revert "pipe language through to xcrun launch"
Jul 20, 2018
d5dae80
pipe the thing through for real this time
Jul 20, 2018
30afc5f
pass the other arg
Aug 2, 2018
d7e8292
Merge branch 'master' into locale
Aug 2, 2018
4dd1215
remove console.logs
Aug 2, 2018
9e00b94
pass language prop to android
Aug 3, 2018
9fb206f
remove a newline
Aug 3, 2018
92e7a42
fix unit tests
Aug 3, 2018
b160757
add a unit test
Aug 3, 2018
1529795
Merge branch 'master' into locale
Sep 9, 2018
697e6bb
re-apply changes and fix unit tests
Sep 9, 2018
19f73da
add a locale option
Sep 9, 2018
12a7a60
update unit test
Sep 9, 2018
8b6f74f
100% test coverage
Sep 9, 2018
9de21e5
temp rename unneeded test files
Sep 9, 2018
c11308d
temp use iphone 6
Sep 9, 2018
9ee6c55
install and link react-native-device-info
Sep 9, 2018
fe31f84
add boilerplate for a language screen
Sep 9, 2018
9cfd763
render current country and locale in test app
Sep 9, 2018
1de2f1e
add e2e test
Sep 9, 2018
8c648b5
add language UI to language screen
Sep 9, 2018
ab62a22
update e2e
Sep 9, 2018
55e256d
Revert "install and link react-native-device-info"
Sep 9, 2018
667475c
e2e test is passing
Sep 9, 2018
3f6bb30
clean up language screen
Sep 9, 2018
971fb09
temp switch emulator
Sep 9, 2018
6b1b446
add language support to test app for android
Sep 9, 2018
50b4d3e
Revert "add language support to test app for android"
Sep 9, 2018
d5d4955
add android support to language screen
Sep 9, 2018
df7967f
update android API
Sep 9, 2018
3768a34
Revert "temp switch emulator"
Sep 9, 2018
85a2ccd
Revert "temp use iphone 6"
Sep 9, 2018
168e42e
Revert "temp rename unneeded test files"
Sep 9, 2018
4691118
uncomment some tests
Sep 9, 2018
f7f8e2f
comment out the not cross-plat test
Sep 9, 2018
28c87f0
Merge branch 'master' into locale-sync-2
Sep 28, 2018
7c7596d
update docs
Sep 28, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion detox/src/devices/Device.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Device {
}
}

const processId = await this.deviceDriver.launchApp(this._deviceId, _bundleId, this._prepareLaunchArgs(baseLaunchArgs));
const processId = await this.deviceDriver.launchApp(this._deviceId, _bundleId, this._prepareLaunchArgs(baseLaunchArgs), params.languageAndLocale);
this._processes[_bundleId] = processId;

await this.deviceDriver.waitUntilReady();
Expand Down
33 changes: 24 additions & 9 deletions detox/src/devices/Device.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,22 @@ describe('Device', () => {

expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"}, undefined);
});

it('launchApp({languageAndLocale}) should launch app with a specific language/locale', async () => {
device = validDevice();

const languageAndLocale = {
language: 'es-MX',
locale: 'es-MX'
};

await device.launchApp({languageAndLocale});

expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"}, languageAndLocale);
});

it(`relaunchApp()`, async () => {
Expand All @@ -107,7 +122,7 @@ describe('Device', () => {
expect(device.deviceDriver.terminate).toHaveBeenCalled();
expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"}, undefined);
});

it(`relaunchApp({newInstance: false}) should not terminate the app before launch`, async () => {
Expand Down Expand Up @@ -144,7 +159,7 @@ describe('Device', () => {
expect(device.deviceDriver.installApp).toHaveBeenCalled();
expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"}, undefined);
});

it(`relaunchApp() without delete when reuse is enabled should not uninstall and install`, async () => {
Expand All @@ -158,7 +173,7 @@ describe('Device', () => {
expect(device.deviceDriver.installApp).not.toHaveBeenCalled();
expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test"}, undefined);
});

it(`relaunchApp() with url should send the url as a param in launchParams`, async () => {
Expand All @@ -167,7 +182,7 @@ describe('Device', () => {

expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-detoxURLOverride": "scheme://some.url"});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-detoxURLOverride": "scheme://some.url"}, undefined);
});

it(`relaunchApp() with url should send the url as a param in launchParams`, async () => {
Expand All @@ -179,7 +194,7 @@ describe('Device', () => {
{
"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-detoxURLOverride": "scheme://some.url", "-detoxSourceAppOverride":
"sourceAppBundleId"
});
}, undefined);
});

it(`launchApp() with disableTouchIndicators should send a boolean switch as a param in launchParams`, async () => {
Expand All @@ -188,7 +203,7 @@ describe('Device', () => {

expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-detoxDisableTouchIndicators": true});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-detoxDisableTouchIndicators": true}, undefined);
});

it(`relaunchApp() with userNofitication should send the userNotification as a param in launchParams`, async () => {
Expand All @@ -200,7 +215,7 @@ describe('Device', () => {

expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-detoxUserNotificationDataURL": "url"});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-detoxUserNotificationDataURL": "url"}, undefined);
});

it(`relaunchApp() with url and userNofitication should throw`, async () => {
Expand Down Expand Up @@ -228,7 +243,7 @@ describe('Device', () => {

expect(device.deviceDriver.launchApp).toHaveBeenCalledWith(device._deviceId,
device._bundleId,
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-arg1": "1", "-arg2": 2});
{"-detoxServer": "ws://localhost:8099", "-detoxSessionId": "test", "-arg1": "1", "-arg2": 2}, undefined);
});

it(`sendToHome() should pass to device driver`, async () => {
Expand Down
2 changes: 1 addition & 1 deletion detox/src/devices/drivers/AndroidDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class AndroidDriver extends DeviceDriverBase {
}
}

async launchApp(deviceId, bundleId, launchArgs) {
async launchApp(deviceId, bundleId, launchArgs, languageAndLocale) {
await this.emitter.emit('beforeLaunchApp', { deviceId, bundleId, launchArgs });

if (!this.instrumentationProcess) {
Expand Down
4 changes: 2 additions & 2 deletions detox/src/devices/drivers/SimulatorDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ class SimulatorDriver extends IosDriver {
await this._applesimutils.uninstall(deviceId, bundleId);
}

async launchApp(deviceId, bundleId, launchArgs) {
async launchApp(deviceId, bundleId, launchArgs, languageAndLocale) {
await this.emitter.emit('beforeLaunchApp', {bundleId, deviceId, launchArgs});
const pid = await this._applesimutils.launch(deviceId, bundleId, launchArgs);
const pid = await this._applesimutils.launch(deviceId, bundleId, launchArgs, languageAndLocale);
await this.emitter.emit('launchApp', {bundleId, deviceId, launchArgs, pid});

return pid;
Expand Down
18 changes: 13 additions & 5 deletions detox/src/devices/ios/AppleSimUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ class AppleSimUtils {
}
}

async launch(udid, bundleId, launchArgs) {
async launch(udid, bundleId, launchArgs, languageAndLocale) {
const frameworkPath = await environment.getFrameworkPath();
const logsInfo = new LogsInfo(udid);
const args = this._joinLaunchArgs(launchArgs);

const result = await this._launchMagically(frameworkPath, logsInfo, udid, bundleId, args);
const result = await this._launchMagically(frameworkPath, logsInfo, udid, bundleId, args, languageAndLocale);
return this._parseLaunchId(result);
}

Expand Down Expand Up @@ -250,17 +250,25 @@ class AppleSimUtils {
return _.map(launchArgs, (v, k) => `${k} ${v}`).join(' ').trim();
}

async _launchMagically(frameworkPath, logsInfo, udid, bundleId, args) {
async _launchMagically(frameworkPath, logsInfo, udid, bundleId, args, languageAndLocale) {
const statusLogs = {
trying: `Launching ${bundleId}...`,
successful: `${bundleId} launched. The stdout and stderr logs were recreated, you can watch them with:\n` +
` tail -F ${logsInfo.absJoined}`
};

const launchBin = `/bin/cat /dev/null >${logsInfo.absStdout} 2>${logsInfo.absStderr} && ` +
let launchBin = `/bin/cat /dev/null >${logsInfo.absStdout} 2>${logsInfo.absStderr} && ` +
`SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="${frameworkPath}/Detox" ` +
`/usr/bin/xcrun simctl launch --stdout=${logsInfo.simStdout} --stderr=${logsInfo.simStderr} ` +
`${udid} ${bundleId} --args ${args}`;
`${udid} ${bundleId} --args ${args}`;;

if (!!languageAndLocale && !!languageAndLocale.language) {
launchBin += ` -AppleLanguages "(${languageAndLocale.language})"`;
}

if (!!languageAndLocale && !!languageAndLocale.locale) {
launchBin += ` -AppleLocale ${languageAndLocale.locale}`;
}

return await exec.execWithRetriesAndLogs(launchBin, undefined, statusLogs, 1);
}
Expand Down
10 changes: 10 additions & 0 deletions detox/src/devices/ios/AppleSimUtils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,15 @@ describe('AppleSimUtils', () => {
expect(exec.execWithRetriesAndLogs.mock.calls).toMatchSnapshot();
});

it('appends language and locale flags', async () => {
const languageAndLocale = {
language: "es-MS",
locale: "en-US"
};
await uut.launch('udid', 'theBundleId', undefined, languageAndLocale);
expect(exec.execWithRetriesAndLogs.mock.calls).toMatchSnapshot();
});

it('concats args', async () => {
await uut.launch('udid', 'theBundleId', { 'foo': 'bar', 'bob': 'yourUncle' });
expect(exec.execWithRetriesAndLogs.mock.calls).toMatchSnapshot();
Expand Down Expand Up @@ -344,6 +353,7 @@ describe('AppleSimUtils', () => {
const result = await uut.launch('udid', 'theBundleId');
expect(result).toEqual(12345);
});

});

describe('sendToHome', () => {
Expand Down
15 changes: 15 additions & 0 deletions detox/src/devices/ios/__snapshots__/AppleSimUtils.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,21 @@ Array [
]
`;

exports[`AppleSimUtils launch appends language and locale flags 1`] = `
Array [
Array [
"/bin/cat /dev/null >/Users/detox/Library/Developer/CoreSimulator/Devices/udid/data/tmp/detox.last_launch_app_log.out 2>/Users/detox/Library/Developer/CoreSimulator/Devices/udid/data/tmp/detox.last_launch_app_log.err && SIMCTL_CHILD_DYLD_INSERT_LIBRARIES=\\"undefined/Detox\\" /usr/bin/xcrun simctl launch --stdout=/tmp/detox.last_launch_app_log.out --stderr=/tmp/detox.last_launch_app_log.err udid theBundleId --args -AppleLanguages \\"(es-MS)\\" -AppleLocale en-US",
undefined,
Object {
"successful": "theBundleId launched. The stdout and stderr logs were recreated, you can watch them with:
tail -F /Users/detox/Library/Developer/CoreSimulator/Devices/udid/data/tmp/detox.last_launch_app_log.{out,err}",
"trying": "Launching theBundleId...",
},
1,
],
]
`;

exports[`AppleSimUtils launch asks environment for frameworkPath 1`] = `
Array [
Array [
Expand Down
23 changes: 23 additions & 0 deletions detox/test/e2e/06.device.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@ describe('Device', () => {
await expect(element(by.text('Hello!!!'))).toBeVisible();
});

// // Passing on iOS, not implemented on Android
// it('launchApp in a different language', async () => {
// let languageAndLocale = {
// language: "es-MX",
// locale: "es-MX"
// };

// await device.launchApp({newInstance: true, languageAndLocale});
// await element(by.text('Language')).tap();
// await expect(element(by.text(`Current locale: ${languageAndLocale.locale}`))).toBeVisible();
// await expect(element(by.text(`Current language: ${languageAndLocale.language}`))).toBeVisible();

// languageAndLocale = {
// language: "en-US",
// locale: "en-US"
// };

// await device.launchApp({newInstance: true, languageAndLocale});
// await element(by.text('Language')).tap();
// await expect(element(by.text(`Current locale: ${languageAndLocale.locale}`))).toBeVisible();
// await expect(element(by.text(`Current language: ${languageAndLocale.language}`))).toBeVisible();
// });

it('resetContentAndSettings() + install() + relaunch() - should tap successfully', async () => {
await device.resetContentAndSettings();
await device.installApp();
Expand Down
27 changes: 27 additions & 0 deletions detox/test/src/Screens/LanguageScreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { Component } from 'react';
import { Text, View, NativeModules, Platform } from 'react-native';
import _ from 'lodash';

export default class LanguageScreen extends Component {
render() {

const locale = Platform.select({
ios: () => NativeModules.SettingsManager.settings.AppleLocale,
android: () => NativeModules.I18nManager.localeIdentifier
})();

const language = Platform.select({
ios: () => _.take(NativeModules.SettingsManager.settings.AppleLanguages, 1),
android: () => 'Unavailable'
})();

return (
<View style={{ flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 25, marginBottom: 30 }}>Current locale: {locale}</Text>
<Text style={{ fontSize: 25, marginBottom: 30 }}>
Current language: {language}
</Text>
</View>
);
}
}
6 changes: 4 additions & 2 deletions detox/test/src/Screens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import NetworkScreen from './NetworkScreen';
import AnimationsScreen from './AnimationsScreen';
import LocationScreen from './LocationScreen';
import ShakeScreen from './ShakeScreen';
import DatePickerScreen from './DatePickerScreen'
import DatePickerScreen from './DatePickerScreen';
import LanguageScreen from './LanguageScreen';

export {
SanityScreen,
Expand All @@ -29,5 +30,6 @@ export {
AnimationsScreen,
LocationScreen,
ShakeScreen,
DatePickerScreen
DatePickerScreen,
LanguageScreen
};
1 change: 1 addition & 0 deletions detox/test/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class example extends Component {
<Text style={{fontSize: 20, marginBottom: 30}}>
Choose a test
</Text>
{this.renderScreenButton('Language', Screens.LanguageScreen)}
{this.renderScreenButton('Sanity', Screens.SanityScreen)}
{this.renderScreenButton('Matchers', Screens.MatchersScreen)}
{this.renderScreenButton('Actions', Screens.ActionsScreen)}
Expand Down
42 changes: 42 additions & 0 deletions docs/APIRef.DeviceObjectAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,48 @@ Disable touch indicators on iOS.
await device.launchApp({disableTouchIndicators: true});
```

##### 9. Launch with a specific language (iOS only)
Launch the app with a specific system language

Information about accepted values can be found [here](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html).

```js
await device.launchApp({
languageAndLocale: {
language: "es-MX",
locale: "es-MX"
}
});
```

With this API, you can run sets of e2e tests per language. For example:
```js
['es-MX', 'fr-FR', 'pt-BR'].forEach(locale => {
describe(`Test suite in ${locale}`, () => {

beforeAll(async () => {
await device.launchApp({
newInstance: true,
languageAndLocale: {
language: locale,
locale
}
});
});


it('Test A', () => {

})

it('Test B', () => {

})

});
});
```

### `device.relaunchApp(params)`
**Deprecated** Use `device.launchApp(params)` instead. This method is now calling `launchApp({newInstance: true})` for backwards compatibility, it will be removed in Detox 6.X.X.<Br>
Kill and relaunch the app defined in the current [`configuration`](APIRef.Configuration.md).
Expand Down