fix modal/toaster (queue)

pull/5370/head
yann300 3 years ago
parent 0a90116625
commit 506434803f
  1. 2
      apps/remix-ide-e2e/src/local-plugin/src/app/app.tsx
  2. 4
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  3. 4
      apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts
  4. 72
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  5. 2
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  6. 1
      apps/remix-ide/src/remixEngine.js
  7. 97
      libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts

@ -33,7 +33,7 @@ function App () {
useEffect(() => { useEffect(() => {
client.onload(async () => { client.onload(async () => {
const customProfiles = ['menuicons', 'tabs', 'solidityUnitTesting', 'hardhat-provider'] const customProfiles = ['menuicons', 'tabs', 'solidityUnitTesting', 'hardhat-provider', 'notification']
client.testCommand = async (data: any) => { client.testCommand = async (data: any) => {
console.log(data) console.log(data)

@ -84,9 +84,9 @@ module.exports = {
.openFile('Untitled.sol') .openFile('Untitled.sol')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') .click('*[data-id="settingsWeb3Mode"]')
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]') .waitForElementPresent('[data-id="envNotification-modal-footer-ok-react"]')
.execute(function () { .execute(function () {
const modal = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any const modal = document.querySelector('[data-id="envNotification-modal-footer-ok-react"]') as any
modal.click() modal.click()
}) })

@ -79,9 +79,9 @@ module.exports = {
.openFile('Untitled.sol') .openFile('Untitled.sol')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') .click('*[data-id="settingsWeb3Mode"]')
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]') .waitForElementPresent('[data-id="envNotification-modal-footer-ok-react"]')
.execute(function () { .execute(function () {
const modal = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any const modal = document.querySelector('[data-id="envNotification-modal-footer-ok-react"]') as any
modal.click() modal.click()
}) })

@ -64,12 +64,16 @@ const clearPayLoad = async (browser: NightwatchBrowser) => {
}) })
} }
const clickButton = async (browser: NightwatchBrowser, buttonText: string) => { const clickButton = async (browser: NightwatchBrowser, buttonText: string, waitResult: boolean = true) => {
return new Promise((resolve) => { return new Promise((resolve) => {
browser.useXpath().waitForElementVisible(`//*[@data-id='${buttonText}']`).pause(100) browser.useXpath().waitForElementVisible(`//*[@data-id='${buttonText}']`).pause(100)
.click(`//*[@data-id='${buttonText}']`, async () => { .click(`//*[@data-id='${buttonText}']`, async () => {
await checkForAcceptAndRemember(browser) await checkForAcceptAndRemember(browser)
browser.waitForElementContainsText('//*[@id="callStatus"]', 'stop').perform(() => resolve(true)) if (waitResult) {
browser.waitForElementContainsText('//*[@id="callStatus"]', 'stop').perform(() => resolve(true))
} else {
resolve(true)
}
}) })
}) })
} }
@ -103,7 +107,7 @@ const checkForAcceptAndRemember = async function (browser: NightwatchBrowser) {
* @return {Promise} * @return {Promise}
*/ */
const clickAndCheckLog = async (browser: NightwatchBrowser, buttonText: string, methodResult: any, eventResult: any, payload: any) => { const clickAndCheckLog = async (browser: NightwatchBrowser, buttonText: string, methodResult: any, eventResult: any, payload: any, waitResult: boolean = true) => {
if (payload) { if (payload) {
await setPayload(browser, payload) await setPayload(browser, payload)
} else { } else {
@ -112,10 +116,14 @@ const clickAndCheckLog = async (browser: NightwatchBrowser, buttonText: string,
if (methodResult && typeof methodResult !== 'string') { methodResult = JSON.stringify(methodResult) } if (methodResult && typeof methodResult !== 'string') { methodResult = JSON.stringify(methodResult) }
if (eventResult && typeof eventResult !== 'string') { eventResult = JSON.stringify(eventResult) } if (eventResult && typeof eventResult !== 'string') { eventResult = JSON.stringify(eventResult) }
if (buttonText) { if (buttonText) {
await clickButton(browser, buttonText) await clickButton(browser, buttonText, waitResult)
}
if (methodResult) {
await debugValues(browser, 'methods', methodResult)
}
if (eventResult) {
await debugValues(browser, 'events', eventResult)
} }
await debugValues(browser, 'methods', methodResult)
await debugValues(browser, 'events', eventResult)
} }
const assertPluginIsActive = function (browser: NightwatchBrowser, id: string, shouldBeVisible: boolean) { const assertPluginIsActive = function (browser: NightwatchBrowser, id: string, shouldBeVisible: boolean) {
@ -364,5 +372,57 @@ module.exports = {
const result = '{"jsonrpc":"2.0","result":true,"id":9999}' const result = '{"jsonrpc":"2.0","result":true,"id":9999}'
await clickAndCheckLog(browser, 'hardhat-provider:sendAsync', result, null, request) await clickAndCheckLog(browser, 'hardhat-provider:sendAsync', result, null, request)
}) })
},
// MODAL
'Should open 2 alert in a row and trigger 2 toaster in between #group9': function (browser: NightwatchBrowser) {
browser
.frameParent()
.useCss()
.addFile('test_modal.js', { content: testModalToasterApi })
.executeScript('remix.execute(\'test_modal.js\')')
.clickLaunchIcon('localPlugin')
.useXpath()
// @ts-ignore
.frame(0)
.perform(async () => {
await clickAndCheckLog(browser, 'notification:toast', null, null, 'message toast from local plugin', false) // create a toast on behalf of the localplugin
await clickAndCheckLog(browser, 'notification:alert', null, null, { message: 'message from local plugin', id: 'test_id_1_local_plugin' }, false) // create an alert on behalf of the localplugin
})
.frameParent()
.useCss()
// check the local plugin notifications
.waitForElementVisible('*[data-id="test_id_1_local_pluginModalDialogModalBody-react"]')
.assert.containsText('*[data-id="test_id_1_local_pluginModalDialogModalBody-react"]', 'message from local plugin')
.modalFooterOKClick('test_id_1_local_plugin')
// check the script runner notifications
.waitForElementVisible('*[data-id="test_id_1_ModalDialogModalBody-react"]')
.assert.containsText('*[data-id="test_id_1_ModalDialogModalBody-react"]', 'message 1')
.modalFooterOKClick('test_id_1_')
.waitForElementVisible('*[data-id="test_id_2_ModalDialogModalBody-react"]')
.assert.containsText('*[data-id="test_id_2_ModalDialogModalBody-react"]', 'message 2')
.modalFooterOKClick('test_id_2_')
// check the toasters
.waitForElementVisible('*[data-shared="tooltipPopup"]')
.waitForElementContainsText('*[data-shared="tooltipPopup"]', 'message toast from local plugin')
.waitForElementContainsText('*[data-shared="tooltipPopup"]', 'I am a toast')
.waitForElementContainsText('*[data-shared="tooltipPopup"]', 'I am a re-toast')
} }
} }
const testModalToasterApi = `
// Right click on the script name and hit "Run" to execute
(async () => {
try {
setTimeout(() => {
console.log('test .. ')
remix.call('notification', 'alert', { message: 'message 1', id: 'test_id_1_' })
remix.call('notification', 'toast', 'I am a toast')
remix.call('notification', 'toast', 'I am a re-toast')
remix.call('notification', 'alert', { message: 'message 2', id: 'test_id_2_' })
}, 500)
} catch (e) {
console.log(e.message)
}
})() `

@ -51,7 +51,7 @@ module.exports = {
.click('*[data-id="terminalClearConsole"]') // clear the terminal .click('*[data-id="terminalClearConsole"]') // clear the terminal
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') .click('*[data-id="settingsWeb3Mode"]')
.modalFooterOKClick('udappNotify') .modalFooterOKClick('envNotification')
.executeScript('web3.eth.getAccounts()') .executeScript('web3.eth.getAccounts()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '["', 60000) // we check if an array is present, don't need to check for the content .waitForElementContainsText('*[data-id="terminalJournal"]', '["', 60000) // we check if an array is present, don't need to check for the content
.waitForElementContainsText('*[data-id="terminalJournal"]', '"]', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', '"]', 60000)

@ -14,6 +14,7 @@ export class RemixEngine extends Engine {
if (name === 'slither') return { queueTimeout: 60000 * 4 } // Requires when a solc version is installed if (name === 'slither') return { queueTimeout: 60000 * 4 } // Requires when a solc version is installed
if (name === 'hardhat') return { queueTimeout: 60000 * 4 } if (name === 'hardhat') return { queueTimeout: 60000 * 4 }
if (name === 'localPlugin') return { queueTimeout: 60000 * 4 } if (name === 'localPlugin') return { queueTimeout: 60000 * 4 }
if (name === 'notification') return { queueTimeout: 60000 * 4 }
return { queueTimeout: 10000 } return { queueTimeout: 10000 }
} }

@ -5,49 +5,68 @@ import { AppModal, ModalState } from '../interface'
export const modalReducer = (state: ModalState = ModalInitialState, action: ModalAction) => { export const modalReducer = (state: ModalState = ModalInitialState, action: ModalAction) => {
switch (action.type) { switch (action.type) {
case modalActionTypes.setModal: { case modalActionTypes.setModal: {
let modalList:AppModal[] = state.modals const focusModal: AppModal = {
modalList.push(action.payload) id: action.payload.id || Date.now().toString(),
if (state.modals.length === 1 && state.focusModal.hide === true) { // if it's the first one show it hide: false,
const focusModal: AppModal = { title: action.payload.title,
id: modalList[0].id, message: action.payload.message,
hide: false, okLabel: action.payload.okLabel,
title: modalList[0].title, okFn: action.payload.okFn,
message: modalList[0].message, cancelLabel: action.payload.cancelLabel,
okLabel: modalList[0].okLabel, cancelFn: action.payload.cancelFn,
okFn: modalList[0].okFn, modalType: action.payload.modalType,
cancelLabel: modalList[0].cancelLabel, defaultValue: action.payload.defaultValue,
cancelFn: modalList[0].cancelFn, hideFn: action.payload.hideFn,
modalType: modalList[0].modalType, resolve: action.payload.resolve
defaultValue: modalList[0].defaultValue, }
hideFn: modalList[0].hideFn,
resolve: modalList[0].resolve const modalList: AppModal[] = state.modals.slice()
} modalList.push(focusModal)
modalList = modalList.slice() if (modalList.length === 1) {
modalList.shift() return { ...state, modals: modalList, focusModal }
return { ...state, modals: modalList, focusModal: focusModal } } else {
return { ...state, modals: modalList }
} }
return { ...state, modals: modalList }
} }
case modalActionTypes.handleHideModal: case modalActionTypes.handleHideModal: {
if (state.focusModal.hideFn) { setTimeout(() => {
state.focusModal.hideFn() if (state.focusModal.hideFn) {
} else if (state.focusModal.resolve) { state.focusModal.hideFn()
state.focusModal.resolve(undefined) }
if (state.focusModal.resolve) {
state.focusModal.resolve(undefined)
}
}, 250)
const modalList: AppModal[] = state.modals.slice()
modalList.shift() // remove the current modal from the list
if (modalList.length) {
const focusModal = modalList[0] // extract the next modal from the list
return { ...state, modals: modalList, focusModal }
} else {
state.focusModal = { ...state.focusModal, hide: true, message: null }
return { ...state, modals: [] }
} }
state.focusModal = { ...state.focusModal, hide: true, message: null } }
return { ...state } case modalActionTypes.setToast: {
const toasterList = state.toasters.slice()
case modalActionTypes.setToast: const message = action.payload
state.toasters.push(action.payload) toasterList.push(message)
if (state.toasters.length > 0) { if (toasterList.length === 1) {
const focus = state.toasters[0] return { ...state, toasters: toasterList, focusToaster: action.payload }
state.toasters.shift() } else {
return { ...state, focusToaster: focus } return { ...state, toasters: toasterList }
} }
return { ...state } }
case modalActionTypes.handleToaster: {
case modalActionTypes.handleToaster: const toasterList = state.toasters.slice()
return { ...state, focusToaster: '' } toasterList.shift()
if (toasterList.length) {
const toaster = toasterList[0]
return { ...state, toasters: toasterList, focusToaster: toaster }
} else {
return { ...state, toasters: [] }
}
}
} }
} }

Loading…
Cancel
Save