76 lines
1.6 KiB
JavaScript
76 lines
1.6 KiB
JavaScript
const DEFAULT_TIMEOUT_MS = 20_000;
|
|
|
|
async function launchAppFresh() {
|
|
await device.launchApp({
|
|
newInstance: true,
|
|
permissions: {
|
|
notifications: "YES",
|
|
location: "never",
|
|
microphone: "never",
|
|
},
|
|
});
|
|
}
|
|
|
|
async function reloadApp() {
|
|
await device.reloadReactNative();
|
|
}
|
|
|
|
function byId(id) {
|
|
return element(by.id(id));
|
|
}
|
|
|
|
async function waitForVisibleById(id, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
await waitFor(byId(id)).toBeVisible().withTimeout(timeoutMs);
|
|
}
|
|
|
|
async function expectVisibleById(id) {
|
|
await expect(byId(id)).toBeVisible();
|
|
}
|
|
|
|
async function scrollUntilVisibleById(id, opts = {}) {
|
|
const { timeoutMs = DEFAULT_TIMEOUT_MS, stepPx = 240 } = opts;
|
|
|
|
// Fast-path: already visible.
|
|
try {
|
|
await waitForVisibleById(id, 500);
|
|
return;
|
|
} catch (_e) {
|
|
// Continue to scroll
|
|
}
|
|
|
|
const target = byId(id);
|
|
|
|
// Detox needs an explicit scrollable element to drive scrolling.
|
|
// This app uses RN ScrollView, which maps to different native class names.
|
|
const scrollViews = [
|
|
element(by.type("android.widget.ScrollView")),
|
|
element(by.type("RCTScrollView")),
|
|
];
|
|
|
|
const errors = [];
|
|
for (const scrollView of scrollViews) {
|
|
try {
|
|
await waitFor(target)
|
|
.toBeVisible()
|
|
.whileElement(scrollView)
|
|
.scroll(stepPx, "down");
|
|
return;
|
|
} catch (e) {
|
|
errors.push(e);
|
|
}
|
|
}
|
|
|
|
// Fall back to a direct wait to get a good assertion error.
|
|
await waitForVisibleById(id, timeoutMs);
|
|
}
|
|
|
|
module.exports = {
|
|
DEFAULT_TIMEOUT_MS,
|
|
byId,
|
|
expectVisibleById,
|
|
launchAppFresh,
|
|
reloadApp,
|
|
scrollUntilVisibleById,
|
|
waitForVisibleById,
|
|
};
|
|
|