aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorkumavis <aaron@kumavis.me>2018-03-12 05:52:29 +0800
committerkumavis <aaron@kumavis.me>2018-03-12 05:52:29 +0800
commit0419276958a168f2d7b75c11cfe8d14cf5f39514 (patch)
tree9c408f277c3c495a08b6f33bd8f1a71cb710dedd /test
parent7e56c6b6fa92453559f2510e390fce451de2dead (diff)
downloadtangerine-wallet-browser-0419276958a168f2d7b75c11cfe8d14cf5f39514.tar
tangerine-wallet-browser-0419276958a168f2d7b75c11cfe8d14cf5f39514.tar.gz
tangerine-wallet-browser-0419276958a168f2d7b75c11cfe8d14cf5f39514.tar.bz2
tangerine-wallet-browser-0419276958a168f2d7b75c11cfe8d14cf5f39514.tar.lz
tangerine-wallet-browser-0419276958a168f2d7b75c11cfe8d14cf5f39514.tar.xz
tangerine-wallet-browser-0419276958a168f2d7b75c11cfe8d14cf5f39514.tar.zst
tangerine-wallet-browser-0419276958a168f2d7b75c11cfe8d14cf5f39514.zip
test - poll for element instead of manual timeouts
Diffstat (limited to 'test')
-rw-r--r--test/integration/lib/add-token.js73
-rw-r--r--test/integration/lib/first-time.js80
-rw-r--r--test/integration/lib/send-new-ui.js127
-rw-r--r--test/lib/util.js53
4 files changed, 144 insertions, 189 deletions
diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js
index dd4251cc4..42ed28dca 100644
--- a/test/integration/lib/add-token.js
+++ b/test/integration/lib/add-token.js
@@ -1,4 +1,9 @@
const reactTriggerChange = require('react-trigger-change')
+const {
+ timeout,
+ queryAsync,
+ findAsync,
+} = require('../../lib/util')
QUnit.module('Add token flow')
@@ -13,74 +18,60 @@ QUnit.test('successful add token flow', (assert) => {
})
async function runAddTokenFlowTest (assert, done) {
- const selectState = $('select')
+ const selectState = await queryAsync($, 'select')
selectState.val('add token')
reactTriggerChange(selectState[0])
- await timeout(2000)
-
// Check that no tokens have been added
assert.ok($('.token-list-item').length === 0, 'no tokens added')
// Go to Add Token screen
- let addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
+ let addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button')
assert.ok(addTokenButton[0], 'add token button present')
addTokenButton[0].click()
- await timeout(1000)
-
// Verify Add Token screen
- let addTokenWrapper = $('.add-token__wrapper')
+ let addTokenWrapper = await queryAsync($, '.add-token__wrapper')
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
- let addTokenTitle = $('.add-token__title')
+ let addTokenTitle = await queryAsync($, '.add-token__title')
assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct')
// Cancel Add Token
- const cancelAddTokenButton = $('button.btn-cancel.add-token__button')
+ const cancelAddTokenButton = await queryAsync($, 'button.btn-cancel.add-token__button')
assert.ok(cancelAddTokenButton[0], 'cancel add token button present')
cancelAddTokenButton.click()
- await timeout(1000)
-
assert.ok($('.wallet-view')[0], 'cancelled and returned to account detail wallet view')
// Return to Add Token Screen
- addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
+ addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button')
assert.ok(addTokenButton[0], 'add token button present')
addTokenButton[0].click()
- await timeout(1000)
-
// Verify Add Token Screen
- addTokenWrapper = $('.add-token__wrapper')
- addTokenTitle = $('.add-token__title')
+ addTokenWrapper = await queryAsync($, '.add-token__wrapper')
+ addTokenTitle = await queryAsync($, '.add-token__title')
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct')
// Search for token
- const searchInput = $('input.add-token__input')
+ const searchInput = await queryAsync($, 'input.add-token__input')
searchInput.val('a')
reactTriggerChange(searchInput[0])
- await timeout()
-
// Click token to add
- const tokenWrapper = $('div.add-token__token-wrapper')
+ const tokenWrapper = await queryAsync($, 'div.add-token__token-wrapper')
assert.ok(tokenWrapper[0], 'token found')
const tokenImageProp = tokenWrapper.find('.add-token__token-icon').css('background-image')
const tokenImageUrl = tokenImageProp.slice(5, -2)
tokenWrapper[0].click()
- await timeout()
-
// Click Next button
- let nextButton = $('button.btn-clear.add-token__button')
+ let nextButton = await queryAsync($, 'button.btn-clear.add-token__button')
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
nextButton[0].click()
- await timeout()
-
// Confirm Add token
assert.equal(
$('.add-token__description')[0].textContent,
@@ -90,47 +81,35 @@ async function runAddTokenFlowTest (assert, done) {
assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found')
$('button.btn-clear.add-token__button')[0].click()
- await timeout(2000)
-
// Verify added token image
- let heroBalance = $('.hero-balance')
+ let heroBalance = await queryAsync($, '.hero-balance')
assert.ok(heroBalance, 'rendered hero balance')
assert.ok(tokenImageUrl.indexOf(heroBalance.find('img').attr('src')) > -1, 'token added')
// Return to Add Token Screen
- addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
+ addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button')
assert.ok(addTokenButton[0], 'add token button present')
addTokenButton[0].click()
- await timeout(1000)
-
- const addCustom = $('.add-token__add-custom')
+ const addCustom = await queryAsync($, '.add-token__add-custom')
assert.ok(addCustom[0], 'add custom token button present')
addCustom[0].click()
- await timeout()
-
// Input token contract address
- const customInput = $('input.add-token__add-custom-input')
+ const customInput = await queryAsync($, 'input.add-token__add-custom-input')
customInput.val('0x177af043D3A1Aed7cc5f2397C70248Fc6cDC056c')
reactTriggerChange(customInput[0])
- await timeout(1000)
-
// Click Next button
- nextButton = $('button.btn-clear.add-token__button')
+ nextButton = await queryAsync($, 'button.btn-clear.add-token__button')
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
nextButton[0].click()
- await timeout(1000)
-
// Verify symbol length error since contract address won't return symbol
- const errorMessage = $('.add-token__add-custom-error-message')
+ const errorMessage = await queryAsync($, '.add-token__add-custom-error-message')
assert.ok(errorMessage[0], 'error rendered')
$('button.btn-cancel.add-token__button')[0].click()
- await timeout(2000)
-
// // Confirm Add token
// assert.equal(
// $('.add-token__description')[0].textContent,
@@ -141,13 +120,7 @@ async function runAddTokenFlowTest (assert, done) {
// $('button.btn-clear.add-token__button')[0].click()
// // Verify added token image
- // heroBalance = $('.hero-balance')
+ // heroBalance = await queryAsync($, '.hero-balance')
// assert.ok(heroBalance, 'rendered hero balance')
// assert.ok(heroBalance.find('.identicon')[0], 'token added')
}
-
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-}
diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js
index 764eae47c..052d89518 100644
--- a/test/integration/lib/first-time.js
+++ b/test/integration/lib/first-time.js
@@ -1,6 +1,10 @@
const reactTriggerChange = require('react-trigger-change')
const PASSWORD = 'password123'
const runMascaraFirstTimeTest = require('./mascara-first-time')
+const {
+ timeout,
+ findAsync,
+} = require('../../lib/util')
QUnit.module('first time usage')
@@ -21,20 +25,19 @@ async function runFirstTimeUsageTest(assert, done) {
selectState.val('first time')
reactTriggerChange(selectState[0])
- await timeout(2000)
const app = $('#app-content')
// recurse notices
while (true) {
- const button = app.find('button')
+ const button = await findAsync(app, 'button')
if (button.html() === 'Accept') {
// still notices to accept
- const termsPage = app.find('.markdown')[0]
+ const termsPageRaw = await findAsync(app, '.markdown')
+ const termsPage = (await findAsync(app, '.markdown'))[0]
+ console.log('termsPageRaw', termsPageRaw)
termsPage.scrollTop = termsPage.scrollHeight
- await timeout()
console.log('Clearing notice')
button.click()
- await timeout()
} else {
// exit loop
console.log('No more notices...')
@@ -42,97 +45,68 @@ async function runFirstTimeUsageTest(assert, done) {
}
}
- await timeout()
-
// Scroll through terms
- const title = app.find('h1')[0]
+ const title = (await findAsync(app, 'h1'))[0]
assert.equal(title.textContent, 'MetaMask', 'title screen')
// enter password
- const pwBox = app.find('#password-box')[0]
- const confBox = app.find('#password-box-confirm')[0]
+ const pwBox = (await findAsync(app, '#password-box'))[0]
+ const confBox = (await findAsync(app, '#password-box-confirm'))[0]
pwBox.value = PASSWORD
confBox.value = PASSWORD
- await timeout()
-
// create vault
- const createButton = app.find('button.primary')[0]
+ const createButton = (await findAsync(app, 'button.primary'))[0]
createButton.click()
- await timeout(3000)
-
- const created = app.find('h3')[0]
+ await timeout()
+ const created = (await findAsync(app, 'h3'))[0]
assert.equal(created.textContent, 'Vault Created', 'Vault created screen')
// Agree button
- const button = app.find('button')[0]
+ const button = (await findAsync(app, 'button'))[0]
assert.ok(button, 'button present')
button.click()
- await timeout(1000)
-
- const detail = app.find('.account-detail-section')[0]
+ const detail = (await findAsync(app, '.account-detail-section'))[0]
assert.ok(detail, 'Account detail section loaded.')
- const sandwich = app.find('.sandwich-expando')[0]
+ const sandwich = (await findAsync(app, '.sandwich-expando'))[0]
sandwich.click()
- await timeout()
-
- const menu = app.find('.menu-droppo')[0]
+ const menu = (await findAsync(app, '.menu-droppo'))[0]
const children = menu.children
const logout = children[2]
assert.ok(logout, 'Lock menu item found')
logout.click()
- await timeout(1000)
-
- const pwBox2 = app.find('#password-box')[0]
+ const pwBox2 = (await findAsync(app, '#password-box'))[0]
pwBox2.value = PASSWORD
- const createButton2 = app.find('button.primary')[0]
+ const createButton2 = (await findAsync(app, 'button.primary'))[0]
createButton2.click()
- await timeout(1000)
-
- const detail2 = app.find('.account-detail-section')[0]
+ const detail2 = (await findAsync(app, '.account-detail-section'))[0]
assert.ok(detail2, 'Account detail section loaded again.')
- await timeout()
-
// open account settings dropdown
- const qrButton = app.find('.fa.fa-ellipsis-h')[0]
+ const qrButton = (await findAsync(app, '.fa.fa-ellipsis-h'))[0]
qrButton.click()
- await timeout(1000)
-
// qr code item
- const qrButton2 = app.find('.dropdown-menu-item')[1]
+ const qrButton2 = (await findAsync(app, '.dropdown-menu-item'))[1]
qrButton2.click()
- await timeout(1000)
-
- const qrHeader = app.find('.qr-header')[0]
- const qrContainer = app.find('#qr-container')[0]
+ const qrHeader = (await findAsync(app, '.qr-header'))[0]
+ const qrContainer = (await findAsync(app, '#qr-container'))[0]
assert.equal(qrHeader.textContent, 'Account 1', 'Should show account label.')
assert.ok(qrContainer, 'QR Container found')
- await timeout()
-
- const networkMenu = app.find('.network-indicator')[0]
+ const networkMenu = (await findAsync(app, '.network-indicator'))[0]
networkMenu.click()
- await timeout()
-
- const networkMenu2 = app.find('.network-indicator')[0]
+ const networkMenu2 = (await findAsync(app, '.network-indicator'))[0]
const children2 = networkMenu2.children
children2.length[3]
assert.ok(children2, 'All network options present')
}
-
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-} \ No newline at end of file
diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js
index 3456f2367..07be63a36 100644
--- a/test/integration/lib/send-new-ui.js
+++ b/test/integration/lib/send-new-ui.js
@@ -1,4 +1,9 @@
const reactTriggerChange = require('react-trigger-change')
+const {
+ timeout,
+ queryAsync,
+ findAsync,
+} = require('../../lib/util')
const PASSWORD = 'password123'
@@ -18,83 +23,67 @@ global.ethQuery = {
async function runSendFlowTest(assert, done) {
console.log('*** start runSendFlowTest')
- const selectState = $('select')
+ const selectState = await queryAsync($, 'select')
selectState.val('send new ui')
reactTriggerChange(selectState[0])
- await timeout(2000)
-
- const sendScreenButton = $('button.btn-clear.hero-balance-button')
+ const sendScreenButton = await queryAsync($, 'button.btn-clear.hero-balance-button')
assert.ok(sendScreenButton[1], 'send screen button present')
sendScreenButton[1].click()
- await timeout(1000)
-
- const sendTitle = $('.page-container__title')
+ const sendTitle = await queryAsync($, '.page-container__title')
assert.equal(sendTitle[0].textContent, 'Send ETH', 'Send screen title is correct')
- const sendCopy = $('.page-container__subtitle')
+ const sendCopy = await queryAsync($, '.page-container__subtitle')
assert.equal(sendCopy[0].textContent, 'Only send ETH to an Ethereum address.', 'Send screen has copy')
- const sendFromField = $('.send-v2__form-field')
+ const sendFromField = await queryAsync($, '.send-v2__form-field')
assert.ok(sendFromField[0], 'send screen has a from field')
- let sendFromFieldItemAddress = $('.account-list-item__account-name')
+ let sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 4', 'send from field shows correct account name')
- const sendFromFieldItem = $('.account-list-item')
- sendFromFieldItem[0].click()
-
await timeout()
+ const sendFromFieldItem = await queryAsync($, '.account-list-item')
+ sendFromFieldItem[0].click()
- const sendFromDropdownList = $('.send-v2__from-dropdown__list')
+ const sendFromDropdownList = await queryAsync($, '.send-v2__from-dropdown__list')
assert.equal(sendFromDropdownList.children().length, 4, 'send from dropdown shows all accounts')
console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sendFromDropdownList.children()[1]`, sendFromDropdownList.children()[1]);
sendFromDropdownList.children()[1].click()
- await timeout()
-
- sendFromFieldItemAddress = $('.account-list-item__account-name')
+ sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sendFromFieldItemAddress[0]`, sendFromFieldItemAddress[0]);
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
- let sendToFieldInput = $('.send-v2__to-autocomplete__input')
+ let sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
sendToFieldInput[0].focus()
- await timeout()
-
- const sendToDropdownList = $('.send-v2__from-dropdown__list')
+ const sendToDropdownList = await queryAsync($, '.send-v2__from-dropdown__list')
assert.equal(sendToDropdownList.children().length, 5, 'send to dropdown shows all accounts and address book accounts')
sendToDropdownList.children()[2].click()
- await timeout()
-
const sendToAccountAddress = sendToFieldInput.val()
assert.equal(sendToAccountAddress, '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', 'send to dropdown selects the correct address')
- const sendAmountField = $('.send-v2__form-row:eq(2)')
+ const sendAmountField = await queryAsync($, '.send-v2__form-row:eq(2)')
sendAmountField.find('.currency-display')[0].click()
- await timeout()
-
- const sendAmountFieldInput = sendAmountField.find('input:text')
+ const sendAmountFieldInput = await findAsync(sendAmountField, 'input:text')
sendAmountFieldInput.val('5.1')
reactTriggerChange(sendAmountField.find('input')[0])
- await timeout()
-
- let errorMessage = $('.send-v2__error')
+ let errorMessage = await queryAsync($, '.send-v2__error')
assert.equal(errorMessage[0].textContent, 'Insufficient funds.', 'send should render an insufficient fund error message')
sendAmountFieldInput.val('2.0')
reactTriggerChange(sendAmountFieldInput[0])
-
await timeout()
errorMessage = $('.send-v2__error')
assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected')
- const sendGasField = $('.send-v2__gas-fee-display')
+ const sendGasField = await queryAsync($, '.send-v2__gas-fee-display')
assert.equal(
sendGasField.find('.currency-display__input-wrapper > input').val(),
'0.000198',
@@ -106,120 +95,86 @@ async function runSendFlowTest(assert, done) {
'send gas field should show estimated gas total converted to USD'
)
- const sendGasOpenCustomizeModalButton = $('.send-v2__sliders-icon-container'
- )
+ const sendGasOpenCustomizeModalButton = await queryAsync($, '.send-v2__sliders-icon-container')
sendGasOpenCustomizeModalButton[0].click()
- await timeout(1000)
-
- const customizeGasModal = $('.send-v2__customize-gas')
+ const customizeGasModal = await queryAsync($, '.send-v2__customize-gas')
assert.ok(customizeGasModal[0], 'should render the customize gas modal')
- const customizeGasPriceInput = $('.send-v2__gas-modal-card').first().find('input')
+ const customizeGasPriceInput = (await queryAsync($, '.send-v2__gas-modal-card')).first().find('input')
customizeGasPriceInput.val(50)
reactTriggerChange(customizeGasPriceInput[0])
- const customizeGasLimitInput = $('.send-v2__gas-modal-card').last().find('input')
+ const customizeGasLimitInput = (await queryAsync($, '.send-v2__gas-modal-card')).last().find('input')
customizeGasLimitInput.val(60000)
reactTriggerChange(customizeGasLimitInput[0])
- await timeout()
-
- const customizeGasSaveButton = $('.send-v2__customize-gas__save')
+ const customizeGasSaveButton = await queryAsync($, '.send-v2__customize-gas__save')
customizeGasSaveButton[0].click()
- await timeout()
-
assert.equal(
- sendGasField.find('.currency-display__input-wrapper > input').val(),
+ (await findAsync(sendGasField, '.currency-display__input-wrapper > input')).val(),
'0.003',
'send gas field should show customized gas total'
)
assert.equal(
- sendGasField.find('.currency-display__converted-value')[0].textContent,
+ (await findAsync(sendGasField, '.currency-display__converted-value'))[0].textContent,
'3.60 USD',
'send gas field should show customized gas total converted to USD'
)
- const sendButton = $('button.btn-clear.page-container__footer-button')
+ const sendButton = await queryAsync($, 'button.btn-clear.page-container__footer-button')
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
sendButton[0].click()
-
- await timeout(2000)
+ await timeout()
selectState.val('send edit')
reactTriggerChange(selectState[0])
- await timeout(2000)
-
- const confirmFromName = $('.confirm-screen-account-name').first()
+ const confirmFromName = (await queryAsync($, '.confirm-screen-account-name')).first()
assert.equal(confirmFromName[0].textContent, 'Send Account 2', 'confirm screen should show correct from name')
- const confirmToName = $('.confirm-screen-account-name').last()
+ const confirmToName = (await queryAsync($, '.confirm-screen-account-name')).last()
assert.equal(confirmToName[0].textContent, 'Send Account 3', 'confirm screen should show correct to name')
- const confirmScreenRows = $('.confirm-screen-rows')
+ const confirmScreenRows = await queryAsync($, '.confirm-screen-rows')
const confirmScreenGas = confirmScreenRows.find('.confirm-screen-row-info')[2]
assert.equal(confirmScreenGas.textContent, '3.6 USD', 'confirm screen should show correct gas')
const confirmScreenTotal = confirmScreenRows.find('.confirm-screen-row-info')[3]
assert.equal(confirmScreenTotal.textContent, '2405.36 USD', 'confirm screen should show correct total')
- const confirmScreenBackButton = $('.confirm-screen-back-button')
+ const confirmScreenBackButton = await queryAsync($, '.confirm-screen-back-button')
confirmScreenBackButton[0].click()
- await timeout(1000)
-
- const sendFromFieldItemInEdit = $('.account-list-item')
+ const sendFromFieldItemInEdit = await queryAsync($, '.account-list-item')
sendFromFieldItemInEdit[0].click()
- await timeout()
-
- const sendFromDropdownListInEdit = $('.send-v2__from-dropdown__list')
+ const sendFromDropdownListInEdit = await queryAsync($, '.send-v2__from-dropdown__list')
sendFromDropdownListInEdit.children()[2].click()
- await timeout()
-
- const sendToFieldInputInEdit = $('.send-v2__to-autocomplete__input')
+ const sendToFieldInputInEdit = await queryAsync($, '.send-v2__to-autocomplete__input')
sendToFieldInputInEdit[0].focus()
sendToFieldInputInEdit.val('0xd85a4b6a394794842887b8284293d69163007bbb')
- await timeout()
-
- const sendAmountFieldInEdit = $('.send-v2__form-row:eq(2)')
+ const sendAmountFieldInEdit = await queryAsync($, '.send-v2__form-row:eq(2)')
sendAmountFieldInEdit.find('.currency-display')[0].click()
- await timeout()
-
const sendAmountFieldInputInEdit = sendAmountFieldInEdit.find('input:text')
sendAmountFieldInputInEdit.val('1.0')
reactTriggerChange(sendAmountFieldInputInEdit[0])
- await timeout()
-
- const sendButtonInEdit = $('.btn-clear.page-container__footer-button')
+ const sendButtonInEdit = await queryAsync($, '.btn-clear.page-container__footer-button')
assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
sendButtonInEdit[0].click()
- await timeout()
-
// TODO: Need a way to mock background so that we can test correct transition from editing to confirm
selectState.val('confirm new ui')
reactTriggerChange(selectState[0])
-
- await timeout(2000)
- const confirmScreenConfirmButton = $('.confirm-screen-confirm-button')
+ const confirmScreenConfirmButton = await queryAsync($, '.confirm-screen-confirm-button')
console.log(`+++++++++++++++++++++++++++++++= confirmScreenConfirmButton[0]`, confirmScreenConfirmButton[0]);
confirmScreenConfirmButton[0].click()
- await timeout(2000)
-
- const txView = $('.tx-view')
+ const txView = await queryAsync($, '.tx-view')
console.log(`++++++++++++++++++++++++++++++++ txView[0]`, txView[0]);
assert.ok(txView[0], 'Should return to the account details screen after confirming')
}
-
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-} \ No newline at end of file
diff --git a/test/lib/util.js b/test/lib/util.js
new file mode 100644
index 000000000..626280745
--- /dev/null
+++ b/test/lib/util.js
@@ -0,0 +1,53 @@
+module.exports = {
+ timeout,
+ queryAsync,
+ findAsync,
+ pollUntilTruthy,
+}
+
+function timeout (time) {
+ return new Promise((resolve, reject) => {
+ setTimeout(resolve, time || 1500)
+ })
+}
+
+async function findAsync(container, selector, opts) {
+ try {
+ return await pollUntilTruthy(() => {
+ const result = container.find(selector)
+ if (result.length > 0) return result
+ }, opts)
+ } catch (err) {
+ throw new Error(`Failed to find element within interval: "${selector}"`)
+ }
+}
+
+async function queryAsync(jQuery, selector, opts) {
+ try {
+ return await pollUntilTruthy(() => {
+ const result = jQuery(selector)
+ if (result.length > 0) return result
+ }, opts)
+ } catch (err) {
+ throw new Error(`Failed to find element within interval: "${selector}"`)
+ }
+}
+
+async function pollUntilTruthy(fn, opts = {}){
+ const pollingInterval = opts.pollingInterval || 100
+ const timeoutInterval = opts.timeoutInterval || 5000
+ const start = Date.now()
+ let result
+ while (!result) {
+ // check if timedout
+ const now = Date.now()
+ if ((now - start) > timeoutInterval) {
+ throw new Error(`pollUntilTruthy - failed to return truthy within interval`)
+ }
+ // check for result
+ result = fn()
+ // run again after timeout
+ await timeout(pollingInterval, timeoutInterval)
+ }
+ return result
+}