chore: fix flakey test in suggestionsBrowserKey
This commit is contained in:
parent
c586d4fb21
commit
1499d5bdf5
|
|
@ -8,12 +8,20 @@ const BANNER_DELAY_MS = 2000
|
|||
let reconnectAttempt = 0
|
||||
let reconnectTimer = null
|
||||
let listenersInitialized = false
|
||||
let eventStreamGeneration = 0
|
||||
let eventStreamAbortController = null
|
||||
|
||||
function shouldConnectEventStream () {
|
||||
return window.initResponse && !window.initResponse.loginRequired
|
||||
}
|
||||
|
||||
export function stopEventStream () {
|
||||
eventStreamGeneration++
|
||||
if (eventStreamAbortController != null) {
|
||||
eventStreamAbortController.abort()
|
||||
eventStreamAbortController = null
|
||||
}
|
||||
|
||||
if (reconnectTimer != null) {
|
||||
clearTimeout(reconnectTimer)
|
||||
reconnectTimer = null
|
||||
|
|
@ -105,6 +113,12 @@ async function reconnectWebsocket () {
|
|||
return
|
||||
}
|
||||
|
||||
const streamGeneration = ++eventStreamGeneration
|
||||
if (eventStreamAbortController != null) {
|
||||
eventStreamAbortController.abort()
|
||||
}
|
||||
eventStreamAbortController = new AbortController()
|
||||
|
||||
connectionState.reconnecting = true
|
||||
connectionState.connected = false
|
||||
if (connectionState.disconnectedAt == null) {
|
||||
|
|
@ -115,7 +129,7 @@ async function reconnectWebsocket () {
|
|||
|
||||
try {
|
||||
window.websocketAvailable = true
|
||||
const stream = window.client.eventStream()
|
||||
const stream = window.client.eventStream({}, { signal: eventStreamAbortController.signal })
|
||||
connectionState.connected = true
|
||||
connectionState.reconnecting = false
|
||||
connectionState.disconnectedAt = null
|
||||
|
|
@ -123,15 +137,25 @@ async function reconnectWebsocket () {
|
|||
connectionState.scheduledReconnectDelayMs = 0
|
||||
connectionState.showDisconnectedBanner = false
|
||||
for await (const e of stream) {
|
||||
if (streamGeneration !== eventStreamGeneration) {
|
||||
return
|
||||
}
|
||||
if (reconnectAttempt !== 0) {
|
||||
reconnectAttempt = 0
|
||||
}
|
||||
handleEvent(e)
|
||||
}
|
||||
} catch (err) {
|
||||
if (streamGeneration !== eventStreamGeneration) {
|
||||
return
|
||||
}
|
||||
console.error('Websocket connection failed: ', err)
|
||||
}
|
||||
|
||||
if (streamGeneration !== eventStreamGeneration) {
|
||||
return
|
||||
}
|
||||
|
||||
window.websocketAvailable = false
|
||||
connectionState.connected = false
|
||||
connectionState.reconnecting = false
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<button name="start" type="submit" :disabled="hasConfirmation && !confirmationChecked">
|
||||
<button name="start" type="submit" :disabled="!formReady || (hasConfirmation && !confirmationChecked)">
|
||||
Start
|
||||
</button>
|
||||
<button name="cancel" type="button" @click="handleCancel">
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, nextTick } from 'vue'
|
||||
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { requestReconnectNow } from '../../../js/websocket.js'
|
||||
|
||||
|
|
@ -75,6 +75,7 @@ const hasConfirmation = ref(false)
|
|||
const formErrors = ref({})
|
||||
const actionArguments = ref([])
|
||||
const popupOnStart = ref('')
|
||||
const formReady = ref(false)
|
||||
|
||||
// Computed properties
|
||||
|
||||
|
|
@ -87,23 +88,27 @@ const props = defineProps({
|
|||
|
||||
// Methods
|
||||
async function setup() {
|
||||
const ret = await window.client.getActionBinding({
|
||||
bindingId: props.bindingId
|
||||
})
|
||||
formReady.value = false
|
||||
document.body.removeAttribute('loaded-argument-form')
|
||||
|
||||
const action = ret.action
|
||||
try {
|
||||
const ret = await window.client.getActionBinding({
|
||||
bindingId: props.bindingId
|
||||
})
|
||||
|
||||
title.value = action.title
|
||||
icon.value = action.icon
|
||||
popupOnStart.value = action.popupOnStart || ''
|
||||
actionArguments.value = action.arguments || []
|
||||
argValues.value = {}
|
||||
formErrors.value = {}
|
||||
confirmationChecked.value = false
|
||||
hasConfirmation.value = false
|
||||
const action = ret.action
|
||||
|
||||
// Initialize values from query params or defaults
|
||||
actionArguments.value.forEach(arg => {
|
||||
title.value = action.title
|
||||
icon.value = action.icon
|
||||
popupOnStart.value = action.popupOnStart || ''
|
||||
actionArguments.value = action.arguments || []
|
||||
argValues.value = {}
|
||||
formErrors.value = {}
|
||||
confirmationChecked.value = false
|
||||
hasConfirmation.value = false
|
||||
|
||||
// Initialize values from query params or defaults
|
||||
actionArguments.value.forEach(arg => {
|
||||
if (arg.type === 'confirmation') {
|
||||
hasConfirmation.value = true
|
||||
const paramValue = getQueryParamValue(arg.name)
|
||||
|
|
@ -130,14 +135,20 @@ async function setup() {
|
|||
argValues.value[arg.name] = paramValue !== null ? paramValue : arg.defaultValue || ''
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Run initial validation on all fields after DOM is updated
|
||||
await nextTick()
|
||||
for (const arg of actionArguments.value) {
|
||||
if (arg.type && !arg.type.startsWith('regex:') && arg.type !== 'select' && arg.type !== '' && arg.type !== 'confirmation' && arg.type !== 'checkbox') {
|
||||
await validateArgument(arg, argValues.value[arg.name] || '')
|
||||
// Run initial validation on all fields after DOM is updated
|
||||
await nextTick()
|
||||
for (const arg of actionArguments.value) {
|
||||
if (arg.type && !arg.type.startsWith('regex:') && arg.type !== 'select' && arg.type !== '' && arg.type !== 'confirmation' && arg.type !== 'checkbox') {
|
||||
await validateArgument(arg, argValues.value[arg.name] || '')
|
||||
}
|
||||
}
|
||||
|
||||
formReady.value = true
|
||||
document.body.setAttribute('loaded-argument-form', props.bindingId)
|
||||
} catch (err) {
|
||||
console.error('Failed to load argument form:', err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,6 +405,10 @@ async function startAction(actionArgs) {
|
|||
async function handleSubmit(event) {
|
||||
event.preventDefault()
|
||||
|
||||
if (!formReady.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (popupOnStart.value === 'history') {
|
||||
router.push(`/action/${props.bindingId}`)
|
||||
return
|
||||
|
|
@ -470,6 +485,10 @@ defineExpose({
|
|||
onMounted(() => {
|
||||
setup()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.body.removeAttribute('loaded-argument-form')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,15 @@ async function openArgumentForm() {
|
|||
}),
|
||||
5000
|
||||
)
|
||||
|
||||
await webdriver.wait(
|
||||
new Condition('wait for argument form ready', async () => {
|
||||
const body = await webdriver.findElement(By.css('body'))
|
||||
const attr = await body.getAttribute('loaded-argument-form')
|
||||
return attr != null && attr !== ''
|
||||
}),
|
||||
5000
|
||||
)
|
||||
}
|
||||
|
||||
async function getTestInput() {
|
||||
|
|
@ -62,7 +71,7 @@ async function waitForExecutionComplete() {
|
|||
try {
|
||||
const statusElement = await webdriver.findElement(By.id('execution-dialog-status'))
|
||||
const statusText = await statusElement.getText()
|
||||
return !statusText.includes('Executing')
|
||||
return !statusText.includes('Still running')
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue