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

feat (tailwind): init radio and radio group components #4231

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
16 changes: 16 additions & 0 deletions apps/tailwind-components/components/input/Radio.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<input
v-model="modelValue"
:value="value"
type="radio"
class="w-5 h-5 ml-[6px] mr-2.5 mt-0.5 accent-yellow-500 hover:cursor-pointer"
Copy link
Contributor

Choose a reason for hiding this comment

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

the style looks a little bit different then the design
Screenshot 2024-09-26 at 14 47 42

/>
</template>

<script lang="ts" setup>
defineProps<{
value: string;
}>();

const modelValue = defineModel<string>("");
</script>
64 changes: 64 additions & 0 deletions apps/tailwind-components/components/input/RadioGroup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<template>
<div
:id="`${id}-radio-group`"
class="flex justify-start align-center"
v-for="option in radioOptions"
>
<InputRadio
:id="`${id}-radio-group-${option.value}`"
class="h-auto"
:name="id"
:value="option.value"
v-model="modelValue"
:checked="modelValue === option.value"
@change="$emit('update:modelValue', modelValue)"
/>
<InputLabel
:for="`${id}-radio-group-${option.value}`"
class="hover:cursor-pointer"
>
<template v-if="Object.hasOwn(option, 'label')">
{{ option.label }}
</template>
<template v-else>
{{ option.value }}
</template>
</InputLabel>
</div>
<div class="mt-2" v-if="showClearButton">
<button
type="reset"
:id="`${id}-radio-group-clear`"
:form="`${id}-radio-group`"
@click.prevent="onResetSelection"
>
Clear
</button>
</div>
</template>

<script lang="ts" setup>
interface RadioOptionsDataIF {
value: string;
label?: string;
}

withDefaults(
defineProps<{
id: string;
radioOptions: RadioOptionsDataIF[];
showClearButton?: boolean;
}>(),
{
showClearButton: false,
}
);

const modelValue = ref<string>("");
const emit = defineEmits(["update:modelValue"]);

function onResetSelection() {
modelValue.value = "";
emit("update:modelValue", modelValue.value);
}
</script>
79 changes: 79 additions & 0 deletions apps/tailwind-components/pages/input/Radio.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<h2>Radio Component</h2>
<p>
There are multiple ways to create radio buttons using the tailwind component
libray. You can either create them manually using the
<code>InputRadio</code> and <code>InputLabel</code> components, but this
requires a but more work to link form elements to ensure they are part of
the same group. The examples below demonstrate the three different ways to
use the <code>InputRadioGroup</code> component.
</p>
<ul class="list-disc ml-12 my-2">
<li>Default use: setting the name and values</li>
<li>
Custom labels: passing an array of labels to display instead of the values
</li>
<li>
Showing a clear selection button: rendering the radio inputs with a clear
selection button
</li>
</ul>
<h3>Input radio group examples</h3>
<form class="mt-4 [&_fieldset]:mb-4">
<fieldset class="flex flex-col gap-1">
Copy link
Contributor

Choose a reason for hiding this comment

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

could you add a case where the value is already set ( tests the initial value is correctly set)

<legend class="text-title">
Example 1: Do you agree to the terms and conditions?
</legend>
<InputRadioGroup
id="example-1"
:radioOptions="[{ value: 'No' }, { value: 'Yes' }]"
v-model="question1Response"
/>
<output>
<span>Selection: {{ question1Response }}</span>
</output>
</fieldset>
<fieldset>
<legend class="text-title">
Example 2: Specify the level of security needed.
</legend>
<InputRadioGroup
id="example-2"
v-model="question2Response"
:radioOptions="[
{ value: 'level-1', label: 'Level 1 (A)' },
{ value: 'level-2', label: 'Level 2 (AA)' },
{ value: 'level-3', label: 'Level 3 (AAA)' },
]"
/>
<output>
<span>Selection: {{ question2Response }}</span>
</output>
</fieldset>
<fieldset>
<legend class="text-title">
Example 3: Select the patient's group allocation. If unknown, please
leave blank.
</legend>
<InputRadioGroup
id="example-3"
v-model="question3Response"
:radioOptions="[
{ value: 'control', label: 'Healthy controls' },
{ value: 'intervention', label: 'Experimental cohort' },
{ value: 'placebo', label: 'Placebo cohort' },
]"
:show-clear-button="true"
/>
<output>
<span>Selection: {{ question3Response }}</span>
</output>
</fieldset>
</form>
</template>

<script lang="ts" setup>
const question1Response = ref<string>("");
const question2Response = ref<string>("");
const question3Response = ref<string>("");
</script>
54 changes: 40 additions & 14 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,76 @@
We have e2e tests using playwright
# MOLGENIS End-to-end testing

For the EMX2 component libraries and applications, we use [playwright](https://playwright.dev) for end-to-end testing. In the `e2e` folder, you will find the tests, documentation, and other configurations for running the molgenis E2E tests. In principle, a single file (`*.spec.ts`) contains one or more tests for one component.

## Geting started

To get started with end-to-end testing in MOLGENIS, clone the molgenis-emx2 repository and navigate to the `e2e` directory.

```bash
git clone https://github.com/molgenis/molgenis-emx2
cd e2e
```

If you are creating a new test or fixing an existing test, create a new branch.

```bash
git switch -c fix/e2e-...
git switch -c feat/e2e-...
```

### Install the dependencies

#### To install
```bash
yarn install
```

#### To test against a localhost:8080 run
### Running the tests

To test against a localhost:8080 run the following command.

```bash
npx playwright test
```

#### You can also make the test start/stop emx2
Additionally, you can also start/stop emx2 when running the tests.

```bash
set CI=true && npx playwright test
```

#### You can also run from the molgenis-emx2 project root as follows
Rather than changing the working directory to the `e2e` folder, you can also run the tests from the molgenis-emx2 project root.

```bash
npx playwright test --config e2e --project=chromium
```

The test is part of .circleci/config.yml running that same command.
When running this on a local emx2 server, run the following first (or add it to `.bash_profile`):
The test is part of .circleci/config.yml running that same command. When running this on a local emx2 server, run the following first (or add it to `.bash_profile`):

```bash
export E2E_BASE_URL=http://localhost:8080/
```
IMPORTANT: Do note that some tests will fail unless the local server is set up correctly!

> [!IMPORTANT]
> Some e2e tests will fail unless the local server is set up correctly!

## playwright vscode plugin

[Playwright: Getting started - VS Code](https://playwright.dev/docs/getting-started-vscode)
If you are using vscode, we recommend installing the extension: [Playwright: Getting started - VS Code](https://playwright.dev/docs/getting-started-vscode)

To make the plugin use a local running version of EMX2, add the following to your `settings.json`:
Once installed, you can configure the plugin use a local running version of EMX2. In the `settings.json` file, add the following setting.

```json
"playwright.env": {
"E2E_BASE_URL":"http://localhost:8080/"
},
"E2E_BASE_URL":"http://localhost:8080/"
}
```

When running tests in files which name start with `admin!`, be sure to run `auth.setup.spec.ts` first to ensure login session is defined. See also: https://playwright.dev/docs/auth#authenticating-in-ui-mode
When running tests in files which name start with `admin!`, be sure to run `auth.setup.spec.ts` first to ensure login session is defined. See also: [https://playwright.dev/docs/auth#authenticating-in-ui-mode](https://playwright.dev/docs/auth#authenticating-in-ui-mode).

## Adding tests

We suggest to use the vscode plugin for [creating/recording](https://playwright.dev/docs/codegen) new tests. The `playwright.config.ts` file contains the test configuration including the default server path. It is suggested to use relative server paths ( instead of `https://my-server.com/my-page` use `/my-page` ) to make it possible for test to run against different servers.

By default tests are run for all pull requests, on the server connected to the pull request preview ( i.e. test for pr `007` will by ( default ) run on `https://preview-emx2-pr-007.dev.molgenis.org/`

If creating tests that require being logged in, ensure the filename starts with `admin!`. For more information about this, see https://playwright.dev/docs/auth#basic-shared-account-in-all-tests.
If creating tests that require being logged in, ensure the filename starts with `admin!`. For more information about this, see [https://playwright.dev/docs/auth#basic-shared-account-in-all-tests](https://playwright.dev/docs/auth#basic-shared-account-in-all-tests).
41 changes: 41 additions & 0 deletions e2e/tests/tailwind-components/input/radio.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {test, expect } from "@playwright/test";

test(
"Radio Input: values are properly defined @tw-components @tw-forms @input-radio",
async ({ page }) => {
await page.goto('/apps/tailwind-components/#/input/Radio.story');

await page.getByLabel('No').check();
await expect(page.getByLabel('No')).toHaveValue('No')

await page.getByLabel('Yes').check();
await expect(page.getByLabel('Yes')).toHaveValue('Yes')
}
);

test(
'Radio Input: labels are properly displayed @tw-components @tw-forms @input-radio',
async ({ page }) => {
await page.goto('/apps/tailwind-components/#/input/Radio.story');
await expect(page.getByText('No', { exact: true })).toHaveText('No');
await expect(page.getByText('Yes')).toHaveText('Yes');
}
);

test(
'Radio Input: clear button is shown when indicated @tw-components @tw-forms @input-radio',
async ({ page }) => {
await page.goto('/apps/tailwind-components/#/input/Radio.story');
await expect(page.getByRole('button', { name: 'Clear' })).toBeVisible();
}
)

test(
'Radio Input: inputs are properly reset @tw-components @tw-forms @input-radio',
async ({ page }) => {
await page.goto('/apps/tailwind-components/#/input/Radio.story');
await page.getByLabel("Healthy controls").check();
await page.getByRole('button', { name: 'Clear' }).click();
await expect(page.getByLabel('Healthy controls')).toBeChecked({checked: false});
}
)