Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: modal infrastructure #94

Merged
merged 1 commit into from
Oct 11, 2023

Conversation

raynasorint
Copy link
Contributor

@raynasorint raynasorint commented Sep 27, 2023

Required for the PR #89.

Copy link
Member

@sgotti sgotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raynasorint Thanks for the PR.

  • https://vitest.dev/guide/#configuring-vitest says that if you're using vite to just use the existing vite.config.ts and add the related config there.

  • CI should execute tests.

  • I'll put the test file in the same directory of the source and with .test.ts extension (i.e src/components/modals/configmationDialog.spec.ts

src/components/modals/baseModal.vue Outdated Show resolved Hide resolved
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch 2 times, most recently from af0017b to 57ccfbf Compare September 28, 2023 08:05
@raynasorint raynasorint changed the title [WIP] ui: modal infrastructure ui: modal infrastructure Sep 28, 2023
@raynasorint raynasorint requested a review from sgotti September 28, 2023 08:09
src/components/secrets.vue Outdated Show resolved Hide resolved
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from 57ccfbf to d3dcd4e Compare September 28, 2023 08:41
@raynasorint raynasorint requested a review from sgotti September 28, 2023 08:48
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from d3dcd4e to faa4c21 Compare September 28, 2023 12:03
@raynasorint raynasorint requested a review from sgotti September 28, 2023 12:35
src/components/modals/confirmationDialog.vue Outdated Show resolved Hide resolved
src/components/modals/confirmationDialog.vue Outdated Show resolved Hide resolved
src/components/modals/confirmationDialog.vue Outdated Show resolved Hide resolved
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from faa4c21 to 1ba65ee Compare September 29, 2023 06:44
@raynasorint raynasorint requested a review from sgotti September 29, 2023 07:05
Copy link
Member

@sgotti sgotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raynasorint Modal usually requires also focus trapping (avoid focusing on elements outside the modal using keys like tab). You can add this in this PR or add a TODO and implement it in another PR. I suggest to use vueuse useFocusTrap composable function.

@@ -0,0 +1,20 @@
<template>
<Teleport to="#modals">
<div v-if="show" class="">
Copy link
Member

@sgotti sgotti Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is show here and in confirmationDialog really needed? Isn't enough to put a v-if on the component tag?

@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from 1ba65ee to 795f448 Compare September 29, 2023 09:53
id="modal-confirm"
type="button"
class="btn btn-blue font-bold py-2 px-4 rounded"
@click="$emit('result', true)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reuse emitResult.

id="modal-cancel"
type="button"
class="btn btn-gray font-bold py-2 px-4 rounded"
@click="$emit('result', false)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reuse emitResult.

emit('result', value);
}
const dismissModal = () => {
emit('result', false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reuse emitResult.

><UseFocusTrap :options="options">
<div
class="fixed inset-0 bg-gray-900 bg-opacity-40"
ref="target"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're using the UseFocusTrap component so the ref isn't used and needed.
So, or you only use the component (https://vueuse.org/integrations/useFocusTrap/#using-component) or you only use the composable (https://vueuse.org/integrations/useFocusTrap/#usage).


const dismissModal = () => {
emit('dismiss', false);
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could also add a test on baseModal to test that it works correctly and also focus trap works.

expect(wrapper.emitted()).toHaveProperty('result');
const result = wrapper.emitted('result')!;
expect(result).toHaveLength(1);
expect(result[0]).toStrictEqual([true]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could also add a new test to check the correct handling of baseElement dismiss.

@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch 4 times, most recently from 44f6534 to 14f61f8 Compare October 5, 2023 13:52
@raynasorint raynasorint requested a review from sgotti October 5, 2023 13:57
Copy link
Member

@sgotti sgotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raynasorint Looks like confirmation dialog disappeared. The new basemodal is instead a confirmation dialog... I'm missing something.

Comment on lines 38 to 55
/*test('baseModal esc keyboard', async () => {
const wrapper = mount(baseModal, {
props: { show: true },
global: {
stubs: {
teleport: true,
},
},
});
// Simulate Escape key press
await wrapper.trigger('keydown.esc');

const dismissEvent = wrapper.emitted('result')!;
expect(dismissEvent).toBeCalled();
// expect(dismissEvent).toBeTruthy();
expect(dismissEvent[0]).toEqual([false]);
// expect(dismissEvent[0][0]).toBe(false);
});*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this test is commented out?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the confirmationDialog was removed due some problems with our tests.
I had difficulty with esting the focus trap in more modals.
I prefered to use only baseModal for now, including useConfirmDialog().
I removed the useless line too and export in cost the repeated code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore both dialogs since:

  • they were logically better
  • Changing an implementation because tests don't work isn't the right thing to do.
  • Additionally baseModal is not a "base modal anymore" but a confirmation dialog.

If you have issues with some tests push also them so I can take a look.

Copy link
Contributor Author

@raynasorint raynasorint Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I restored them.
@sgotti I also pushed. Thank you

src/components/modals/baseModal.test.ts Show resolved Hide resolved
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from 14f61f8 to fa2f9e6 Compare October 5, 2023 15:06
@raynasorint raynasorint requested a review from sgotti October 5, 2023 15:35
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch 2 times, most recently from e9b186d to c9951fb Compare October 10, 2023 08:01
@raynasorint
Copy link
Contributor Author

@sgotti I merged your pr,
Thank you

@sgotti
Copy link
Member

sgotti commented Oct 10, 2023

@sgotti I merged your pr,

I don't know what you mean by "merging my pr" but your branch is totally messed up.

You should use git rebase to rebase your commit ON TOP of the current master branch.

@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from c9951fb to 6580633 Compare October 10, 2023 09:41
@raynasorint
Copy link
Contributor Author

@sgotti I merged your pr,

I don't know what you mean by "merging my pr" but your branch is totally messed up.

You should use git rebase to rebase your commit ON TOP of the current master branch.

Sorry my bad. I've finished to rebase now.

Comment on lines 23 to 25
tabbableOptions: {
displayCheck: 'none',
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide some details on why this option has been defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this option to fix an error in my coverage test. The error message was the following:
Error: Your focus-trap must have at least one container with at least one tabbable node in it at all times.
activate node_modules/.pnpm/@vueuse+integrations@9.13.0_focus-trap@7.5.3_universal-cookie@4.0.4_vue@3.2.47/node_modules/@vueuse/integrations/useFocusTrap/component.mjs:11:41
9| let trap;
10| const target = ref();
11| const activate = () => trap && trap.activate();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should only activate this option in tests by mocking it in some ways. See https://github.com/focus-trap/tabbable#testing-in-jsdom

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to mock the test but didn't work anyway.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are many ways to do this. A simple one could be:

diff --git a/src/components/modals/baseModal.vue b/src/components/modals/baseModal.vue
index 8ffb8d6..211023c 100644
--- a/src/components/modals/baseModal.vue
+++ b/src/components/modals/baseModal.vue
@@ -20,10 +20,16 @@ const options: UseFocusTrapOptions = {
   onDeactivate: () => {
     emit('dismiss', false);
   },
-  tabbableOptions: {
-    displayCheck: 'none',
-  },
 };
+
+// tests outside real browsers like jsdom require tabbableOptions.displayCheck
+// set to none (https://github.com/focus-trap/tabbable#testing-in-jsdom)
+if (import.meta.env.TEST) {
+  options.tabbableOptions = {
+    displayCheck: 'none',
+  };
+}
+
 const emit = defineEmits<{
   (e: 'dismiss', value: boolean): void;
 }>();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sgotti somewhere where ? To the same pr?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a new branch on your fork and push a commit with the changes that cause issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the call to it(... never executed the test since you wrapped it by an async function that's never awaited. So removing it(...) made the test run and it failed because it wasn't correct.

This is a working test

import { mount } from '@vue/test-utils';
import baseModal from './baseModal.vue';

test('baseModal', async () => {
  const wrapper = mount(baseModal, {
    props: { show: true },
    global: {
      stubs: {
        teleport: true,
      },
    },
    attachTo: document.body,
  });
  // wait for focus trap to be ready
  await wrapper.vm.$nextTick();

  await wrapper.find('[tabindex="0"]').trigger('keydown', { key: 'Escape' });

  expect(wrapper.emitted().dismiss).toHaveLength(1);
  expect(wrapper.emitted().dismiss[0]).toEqual([false]);
});

The primary issue was that the component by default isn't attached to the document so focus trap wasn't receiving the key events.

Also note the use of expect(wrapper... like explained in the vitest docs to avoid the 'non-null assertion' that's reported as a warning by eslint. You should do the same also in the confirmationDialog tests.

Copy link
Contributor Author

@raynasorint raynasorint Oct 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sgotti thank you so much for the help.
I tried to add the nextTrick() function but I didn't attached the primary component so I think that was the problem.

I put the correct code now.

Thanks

@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch 4 times, most recently from 14219d5 to 19e0b45 Compare October 11, 2023 12:46
@raynasorint raynasorint requested a review from sgotti October 11, 2023 12:47
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from 19e0b45 to 8774cc5 Compare October 11, 2023 12:47
src/components/modals/baseModal.test.ts Show resolved Hide resolved
src/components/modals/confirmationDialog.test.ts Outdated Show resolved Hide resolved
src/components/modals/confirmationDialog.test.ts Outdated Show resolved Hide resolved
@raynasorint raynasorint force-pushed the ui--modal-infrastructure branch from 8774cc5 to fb6aaa3 Compare October 11, 2023 13:28
@sgotti sgotti merged commit a44a1af into agola-io:master Oct 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants