Browse Source

Maintenance: Improve test stability of organization_detail_view_spec.

Dusan Vuckovic 2 years ago
parent
commit
245c25fea8

+ 5 - 7
app/frontend/apps/mobile/components/Organization/OrganizationEditDialog.vue

@@ -10,9 +10,8 @@ import type { OrganizationQuery } from '@shared/graphql/types'
 import { closeDialog } from '@shared/composables/useDialog'
 import { MutationHandler } from '@shared/server/apollo/handler'
 import { type FormData } from '@shared/components/Form/types'
-import { shallowRef } from 'vue'
-import type { FormKitNode } from '@formkit/core'
 import { useOrganizationUpdateMutation } from '@mobile/entities/organization/graphql/mutations/update.api'
+import { useForm } from '@shared/components/Form'
 
 interface Props {
   name: string
@@ -34,9 +33,8 @@ const schema = defineFormSchema([
 ])
 
 const updateQuery = new MutationHandler(useOrganizationUpdateMutation({}))
-const formElement = shallowRef<{ formNode: FormKitNode }>()
 
-const submitForm = () => formElement.value?.formNode.submit()
+const { form, formSubmit, isDisabled } = useForm()
 
 interface OrganizationForm {
   domain: string
@@ -87,18 +85,18 @@ const saveOrganization = async (formData: FormData<OrganizationForm>) => {
 <template>
   <CommonDialog :label="__('Edit')" :name="name">
     <template #before-label>
-      <button class="text-blue" tabindex="0" @click="closeDialog(name)">
+      <button class="text-blue" @click="closeDialog(name)">
         {{ i18n.t('Cancel') }}
       </button>
     </template>
     <template #after-label>
-      <button class="text-blue" tabindex="0" @click="submitForm()">
+      <button class="text-blue" :disabled="isDisabled" @click="formSubmit()">
         {{ i18n.t('Save') }}
       </button>
     </template>
     <Form
       id="edit-organization"
-      ref="formElement"
+      ref="form"
       class="w-full p-4"
       :schema="schema"
       :initial-values="initialValue"

+ 29 - 1
app/frontend/shared/components/Form/Form.vue

@@ -33,6 +33,8 @@ import type {
 import { QueryHandler } from '@shared/server/apollo/handler'
 import { useObjectAttributeLoadFormFields } from '@shared/entities/object-attributes/composables/useObjectAttributeLoadFormFields'
 import { useObjectAttributeFormFields } from '@shared/entities/object-attributes/composables/useObjectAttributeFormFields'
+import testFlags from '@shared/utils/testFlags'
+import { debounce } from 'lodash-es'
 import { useFormUpdaterQuery } from './graphql/queries/formUpdater.api'
 import {
   type FormData,
@@ -115,6 +117,7 @@ const localClass = toRef(props, 'class')
 const emit = defineEmits<{
   (e: 'changed', newValue: unknown, fieldName: string): void
   (e: 'node', node: FormKitNode): void
+  (e: 'settled', isSettled: boolean): void
 }>()
 
 const formNode: Ref<FormKitNode | undefined> = ref()
@@ -191,8 +194,33 @@ const changedValuePlugin = (node: FormKitNode) => {
   })
 }
 
+const formSettledPlugin = (node: FormKitNode) => {
+  node.on(
+    'settled',
+
+    // To give chance to the form to settle all disturbances,
+    //   we debounce the event for some non-zero delay.
+    debounce(($event) => {
+      const isSettled = $event.payload
+      const formName = formNode.value?.context?.id || formNode.value?.name
+
+      if (isSettled) testFlags.set(`${formName}.settled`)
+      else testFlags.clear(`${formName}.settled`)
+
+      emit('settled', isSettled)
+
+      // Limit plugin only to events on the root (form) node.
+      return false
+    }, 250),
+  )
+}
+
 const localFormKitPlugins = computed(() => {
-  return [changedValuePlugin, ...(props.formKitPlugins || [])]
+  return [
+    changedValuePlugin,
+    formSettledPlugin,
+    ...(props.formKitPlugins || []),
+  ]
 })
 
 const formConfig = computed(() => {

+ 17 - 2
app/frontend/shared/components/Form/__tests__/useForm.spec.ts

@@ -3,7 +3,10 @@
 import Form from '@shared/components/Form/Form.vue'
 import useForm from '@shared/components/Form/composable'
 import { getNode, type FormKitNode } from '@formkit/core'
-import { renderComponent } from '@tests/support/components'
+import {
+  type ExtendedRenderResult,
+  renderComponent,
+} from '@tests/support/components'
 
 const wrapperParameters = {
   form: true,
@@ -12,7 +15,7 @@ const wrapperParameters = {
 }
 
 // Initialize a form component.
-renderComponent(Form, {
+const wrapper: ExtendedRenderResult = renderComponent(Form, {
   ...wrapperParameters,
   attrs: {
     id: 'test-form',
@@ -78,4 +81,16 @@ describe('useForm', () => {
       text: 'Some text',
     })
   })
+
+  it('use form submit', () => {
+    const { form, formSubmit } = useForm()
+
+    form.value = {
+      formNode: getNode('test-form') as FormKitNode,
+    }
+
+    formSubmit()
+
+    expect(wrapper.emitted().submit).toBeTruthy()
+  })
 })

+ 5 - 0
app/frontend/shared/components/Form/composable.ts

@@ -33,6 +33,10 @@ const useForm = () => {
     node.value?.reset()
   }
 
+  const formSubmit = () => {
+    node.value?.submit()
+  }
+
   return {
     form,
     node,
@@ -45,6 +49,7 @@ const useForm = () => {
     isSubmitted,
     isDisabled,
     formReset,
+    formSubmit,
   }
 }
 

+ 4 - 0
spec/system/apps/mobile/organization/organization_detail_view_spec.rb

@@ -38,6 +38,8 @@ RSpec.describe 'Mobile > Organization > Can view organization', type: :system, a
 
       click('button', text: 'Edit')
 
+      wait_for_test_flag('edit-organization.settled')
+
       within('#dialog-organization-edit') do
         find('[name="note"]').send_keys('edit field')
         click('button', text: 'Save')
@@ -63,6 +65,8 @@ RSpec.describe 'Mobile > Organization > Can view organization', type: :system, a
 
       click('button', text: 'Edit')
 
+      wait_for_test_flag('edit-organization.settled')
+
       within('#dialog-organization-edit') do
         fill_in('name', with: 'new name')
         fill_in(attribute.name, with: 'some text')