diff --git a/public/locales/en/enrolment.json b/public/locales/en/enrolment.json index 65dd89b9..e6b929ce 100644 --- a/public/locales/en/enrolment.json +++ b/public/locales/en/enrolment.json @@ -17,6 +17,13 @@ "labelIsSharingDataAccepted": "I agree to share my information with the event organizer", "labelLanguage": "Language", "labelNotificationLanguage": "Language used in notifications", + "culturalRoute": { + "labelIsPartOf": "The visit is part of the cultural route", + "labelNoOrUnknown": "No / I don't know", + "labelYes": "Yes", + "helperText": "Cultural routes are implementation proposals for the City of Helsinki's cultural education plan from early childhood education to upper secondary education. Read more", + "readMoreUrl": "/en/cms-page/cultural-education/cultural-routes" + }, "person": { "labelEmailAddress": "Email address", "labelName": "Name", diff --git a/public/locales/fi/enrolment.json b/public/locales/fi/enrolment.json index 0f1506b3..db66230c 100644 --- a/public/locales/fi/enrolment.json +++ b/public/locales/fi/enrolment.json @@ -17,6 +17,13 @@ "labelIsSharingDataAccepted": "Hyväksyn tietojeni jakamisen tapahtuman järjestäjän kanssa", "labelLanguage": "Kieli", "labelNotificationLanguage": "Ilmoitusten kieli", + "culturalRoute": { + "labelIsPartOf": "Käynti sisältyy kulttuuripolkuun", + "labelNoOrUnknown": "Ei / en tiedä", + "labelYes": "Kyllä", + "helperText": "Kulttuuripolut ovat Helsingin kaupungin kulttuurikasvatussuunnitelman toteutusehdotuksia varhaiskasvatuksesta toiselle asteelle. Lue lisää kulttuuripoluista", + "readMoreUrl": "/fi/cms-page/kulttuurikasvatus/kulttuuripolulla-kulttuuria-kaikille" + }, "person": { "labelEmailAddress": "Sähköpostiosoite", "labelName": "Nimi", diff --git a/public/locales/sv/enrolment.json b/public/locales/sv/enrolment.json index 19a9da88..1b6437d0 100644 --- a/public/locales/sv/enrolment.json +++ b/public/locales/sv/enrolment.json @@ -17,6 +17,13 @@ "labelIsSharingDataAccepted": "Jag samtycker till att dela mina uppgifter med arrangören av evenemanget.", "labelLanguage": "Språk", "labelNotificationLanguage": "Språket för meddelanden", + "culturalRoute": { + "labelIsPartOf": "Besöket ingår i kulturstigen", + "labelNoOrUnknown": "Nej / jag vet inte", + "labelYes": "Ja", + "helperText": "Kulturstigarna är förslag på genomförande av Helsingfors stads kulturfostransplan från småbarnspedagogik till gymnasieutbildning. Läs mer om kulturstigarna", + "readMoreUrl": "/sv/cms-page/kulturpedagogik/kulturstigen-kultur-for-alla" + }, "person": { "labelEmailAddress": "E-post", "labelName": "Namn", diff --git a/src/common/components/formikPersist/FormikPersist.tsx b/src/common/components/formikPersist/FormikPersist.tsx index 956a26bd..41ab1dc5 100644 --- a/src/common/components/formikPersist/FormikPersist.tsx +++ b/src/common/components/formikPersist/FormikPersist.tsx @@ -1,5 +1,8 @@ import { FormikProps, useFormikContext } from 'formik'; +import cloneDeep from 'lodash/cloneDeep'; +import get from 'lodash/get'; import isEqual from 'lodash/isEqual'; +import set from 'lodash/set'; import * as React from 'react'; import useIsMounted from '../../../hooks/useIsMounted'; @@ -26,6 +29,8 @@ export interface PersistProps { debounceTime?: number; isSessionStorage?: boolean; initialValues: Record; + // Dot-notation paths of fields that are restored using initial values: + alwaysFreshFields?: string[]; } const FormikPersist = ({ @@ -33,6 +38,7 @@ const FormikPersist = ({ isSessionStorage = false, name, initialValues, + alwaysFreshFields = [], }: PersistProps): null => { const isMounted = useIsMounted(); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -78,7 +84,12 @@ const FormikPersist = ({ storedFormikStateObject && objectStructureMatches(initialValues, storedFormikStateObject.values) ) { - formik.setValues(storedFormikStateObject.values, true); + const valuesToRestore = cloneDeep(storedFormikStateObject.values); + // Restore fresh fields with their initial values instead of stored ones: + for (const path of alwaysFreshFields) { + set(valuesToRestore, path, get(initialValues, path)); + } + formik.setValues(valuesToRestore, true); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/common/components/formikPersist/__tests__/FormikPersist.test.tsx b/src/common/components/formikPersist/__tests__/FormikPersist.test.tsx index 38cbdc2c..83bf4633 100644 --- a/src/common/components/formikPersist/__tests__/FormikPersist.test.tsx +++ b/src/common/components/formikPersist/__tests__/FormikPersist.test.tsx @@ -121,3 +121,56 @@ test('attempts to rehydrate on mount if session storage is true on props', async ); }); }); + +test('alwaysFreshFields resets listed fields to their initial values', async () => { + let injected: FormikProps<{ regularField: string; freshField: string }>; + + (localStorage.getItem as jest.Mock).mockReturnValueOnce( + JSON.stringify({ + ...defaultState, + values: { + regularField: 'Persisted value of regular field', + freshField: 'Persisted value of fresh field', + }, + }) + ); + + render( + + {(props: FormikProps<{ regularField: string; freshField: string }>) => { + injected = props; + + return ( +
+ +
+ ); + }} +
+ ); + + expect(localStorage.getItem).toHaveBeenCalled(); + + // regularField is not in alwaysFreshFields, so it should be restored from storage + expect(injected!.values.regularField).toEqual( + 'Persisted value of regular field' + ); + // freshField is in alwaysFreshFields, so it must be reset to its initial value: + expect(injected!.values.freshField).toEqual( + 'Initial value of fresh field in Persist' + ); +}); diff --git a/src/domain/enrolment/__tests__/utils.test.ts b/src/domain/enrolment/__tests__/utils.test.ts new file mode 100644 index 00000000..2769523c --- /dev/null +++ b/src/domain/enrolment/__tests__/utils.test.ts @@ -0,0 +1,27 @@ +import { IsPartOfCulturalRoute } from '../enrolmentForm/constants'; +import { validIsPartOfCulturalRouteToBoolean } from '../utils'; + +describe('validIsPartOfCulturalRouteToBoolean', () => { + test.each([ + IsPartOfCulturalRoute.YES, // Test that the enum version works + 'YES', // Test that the string version also works + ])('validIsPartOfCulturalRouteToBoolean(%p) returns true', (input) => { + expect(validIsPartOfCulturalRouteToBoolean(input)).toBe(true); + }); + + test.each([ + IsPartOfCulturalRoute.NO_OR_UNKNOWN, // Test that the enum version works + 'NO_OR_UNKNOWN', // Test that the string version also works + ])('validIsPartOfCulturalRouteToBoolean(%p) returns false', (input) => { + expect(validIsPartOfCulturalRouteToBoolean(input)).toBe(false); + }); + + test.each(['', ' ', 'yes', 'NO', 'unanswered', null, undefined, true, 0, 1])( + 'validIsPartOfCulturalRouteToBoolean(%p) throws on invalid value', + (input) => { + expect(() => validIsPartOfCulturalRouteToBoolean(input)).toThrow( + `Invalid isPartOfCulturalRoute value ${input}` + ); + } + ); +}); diff --git a/src/domain/enrolment/enrolmentForm/EnrolmentForm.tsx b/src/domain/enrolment/enrolmentForm/EnrolmentForm.tsx index a938c59f..bf9611be 100644 --- a/src/domain/enrolment/enrolmentForm/EnrolmentForm.tsx +++ b/src/domain/enrolment/enrolmentForm/EnrolmentForm.tsx @@ -17,6 +17,7 @@ import { nameToLabelPath, } from './constants'; import styles from './enrolmentForm.module.scss'; +import IsPartOfCulturalRouteField from './IsPartOfCulturalRouteField'; import getValidationSchema from './ValidationSchema'; import ErrorMessage from '../../../common/components/form/ErrorMessage'; import CheckboxField from '../../../common/components/form/fields/CheckboxField'; @@ -103,6 +104,7 @@ const EnrolmentForm: React.FC = ({

{t('enrolment:enrolmentForm.studyGroup.titleNotifier')}

= ({ + + + +

{t('enrolment:enrolmentForm.studyGroup.titleGroup')}

diff --git a/src/domain/enrolment/enrolmentForm/IsPartOfCulturalRouteField.tsx b/src/domain/enrolment/enrolmentForm/IsPartOfCulturalRouteField.tsx new file mode 100644 index 00000000..c6741693 --- /dev/null +++ b/src/domain/enrolment/enrolmentForm/IsPartOfCulturalRouteField.tsx @@ -0,0 +1,62 @@ +import { Link } from '@city-of-helsinki/react-helsinki-headless-cms'; +import { useField } from 'formik'; +import { RadioButton, SelectionGroup } from 'hds-react'; +import { Trans, useTranslation } from 'next-i18next'; +import React from 'react'; + +import { IsPartOfCulturalRoute, nameToLabelPath } from './constants'; +import type { I18nNamespace } from '../../../types'; + +type Props = { + formikFieldName: string; +}; + +/** + * React component for "Is part of cultural route?" field in the enrolment form, + * with choices of "No / I don't know" and "Yes". + */ +const IsPartOfCulturalRouteField: React.FC = ({ formikFieldName }) => { + const { t } = useTranslation(); + const [field, meta] = useField(formikFieldName); + const errorText = meta.touched && meta.error ? t(meta.error) : undefined; + const readMoreUrl = t('enrolment:enrolmentForm.culturalRoute.readMoreUrl'); + + return ( + }} + /> + } + > + + + + ); +}; + +export default IsPartOfCulturalRouteField; diff --git a/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx b/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx index 7fbcfd69..c63443ac 100644 --- a/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx +++ b/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx @@ -1,5 +1,6 @@ import * as Yup from 'yup'; +import { IsPartOfCulturalRoute } from './constants'; import { VALIDATION_MESSAGE_KEYS } from '../../app/forms/constants'; type EnrolmentFormValidationSchemaProps = { @@ -14,6 +15,12 @@ export default function getValidationSchema({ isQueueEnrolment, }: EnrolmentFormValidationSchemaProps) { return Yup.object().shape({ + isPartOfCulturalRoute: Yup.string() + .oneOf( + [IsPartOfCulturalRoute.NO_OR_UNKNOWN, IsPartOfCulturalRoute.YES], + VALIDATION_MESSAGE_KEYS.STRING_REQUIRED + ) + .required(VALIDATION_MESSAGE_KEYS.STRING_REQUIRED), hasEmailNotification: Yup.bool().oneOf( [true], 'enrolment:enrolmentForm.validation.hasEmailNotification' diff --git a/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx b/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx index 5b0d460d..225eac71 100644 --- a/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx +++ b/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx @@ -23,7 +23,10 @@ import { within, sleep, } from '../../../../utils/testUtils'; -import { defaultEnrolmentInitialValues } from '../constants'; +import { + defaultEnrolmentInitialValues, + IsPartOfCulturalRoute, +} from '../constants'; import EnrolmentForm, { Props } from '../EnrolmentForm'; configure({ defaultHidden: true }); @@ -113,6 +116,14 @@ test('renders form and user can fill it and submit and form is saved to local st // // close dropdown + // Answer "Is part of cultural route?" question + const culturalRouteGroup = await screen.findByRole('group', { + name: /käynti sisältyy kulttuuripolkuun/i, + }); + await userEvent.click( + within(culturalRouteGroup).getByRole('radio', { name: /kyllä/i }) + ); + await userEvent.click(screen.getByRole('combobox', { name: /luokka-aste/i })); await userEvent.type(screen.getByLabelText(/lapsia/i), '10'); @@ -411,6 +422,7 @@ if (isFeatureEnabled('FORMIK_PERSIST')) { isSameResponsiblePerson: true, isSharingDataAccepted: false, isMandatoryAdditionalInformationRequired: false, + isPartOfCulturalRoute: IsPartOfCulturalRoute.NO_OR_UNKNOWN, language: '', studyGroup: { person: { @@ -504,6 +516,23 @@ if (isFeatureEnabled('FORMIK_PERSIST')) { expect( screen.getByRole('combobox', { name: /luokka-aste/i }) ).toHaveTextContent('1. luokka'); + + // Test that "Is part of cultural route?" question is not answered, + // because this field should not be restored from local storage: + const culturalRouteGroup = await screen.findByRole('group', { + name: /käynti sisältyy kulttuuripolkuun/i, + }); + const isNotPartOfCulturalRoute = within(culturalRouteGroup).getByRole( + 'radio', + { name: /ei \/ en tiedä/i } + ); + const isPartOfCulturalRoute = within(culturalRouteGroup).getByRole( + 'radio', + { name: /kyllä/i } + ); + expect(isNotPartOfCulturalRoute).not.toBeChecked(); + expect(isPartOfCulturalRoute).not.toBeChecked(); + const childrenCountInput = screen.getByRole('spinbutton', { name: /lapsia \*/i, }); diff --git a/src/domain/enrolment/enrolmentForm/__tests__/IsPartOfCulturalRouteField.test.tsx b/src/domain/enrolment/enrolmentForm/__tests__/IsPartOfCulturalRouteField.test.tsx new file mode 100644 index 00000000..65063cc8 --- /dev/null +++ b/src/domain/enrolment/enrolmentForm/__tests__/IsPartOfCulturalRouteField.test.tsx @@ -0,0 +1,124 @@ +import { Formik } from 'formik'; +import * as React from 'react'; + +import { + render, + screen, + userEvent, + within, + configure, + waitFor, +} from '../../../../utils/testUtils'; +import { IsPartOfCulturalRoute } from '../constants'; +import IsPartOfCulturalRouteField from '../IsPartOfCulturalRouteField'; +import getValidationSchema from '../ValidationSchema'; + +configure({ defaultHidden: true }); + +const renderComponent = (initialValue: IsPartOfCulturalRoute | '' = '') => + render( + + {({ submitForm }) => ( + <> + + + + )} + + ); + +const getGroup = () => + screen.findByRole('group', { name: /käynti sisältyy kulttuuripolkuun/i }); + +const getNoOrUnknownRadio = (group: HTMLElement) => + within(group).getByRole('radio', { name: /ei \/ en tiedä/i }); + +const getYesRadio = (group: HTMLElement) => + within(group).getByRole('radio', { name: /kyllä/i }); + +describe('IsPartOfCulturalRouteField', () => { + it('renders the selection group with both radio options', async () => { + renderComponent(); + const group = await getGroup(); + expect(getNoOrUnknownRadio(group)).toBeInTheDocument(); + expect(getYesRadio(group)).toBeInTheDocument(); + }); + + it('has no radio checked when initial value is empty', async () => { + renderComponent(''); + const group = await getGroup(); + expect(getNoOrUnknownRadio(group)).not.toBeChecked(); + expect(getYesRadio(group)).not.toBeChecked(); + }); + + it('checks "No / I don\'t know" when initial value is NO_OR_UNKNOWN', async () => { + renderComponent(IsPartOfCulturalRoute.NO_OR_UNKNOWN); + const group = await getGroup(); + expect(getNoOrUnknownRadio(group)).toBeChecked(); + expect(getYesRadio(group)).not.toBeChecked(); + }); + + it('checks "Yes" when initial value is YES', async () => { + renderComponent(IsPartOfCulturalRoute.YES); + const group = await getGroup(); + expect(getNoOrUnknownRadio(group)).not.toBeChecked(); + expect(getYesRadio(group)).toBeChecked(); + }); + + it('checks only "Yes" radio after clicking it', async () => { + renderComponent(''); + const group = await getGroup(); + await userEvent.click(getYesRadio(group)); + expect(getYesRadio(group)).toBeChecked(); + expect(getNoOrUnknownRadio(group)).not.toBeChecked(); + }); + + it('checks only "No / I don\'t know" radio after clicking it', async () => { + renderComponent(''); + const group = await getGroup(); + await userEvent.click(getNoOrUnknownRadio(group)); + expect(getNoOrUnknownRadio(group)).toBeChecked(); + expect(getYesRadio(group)).not.toBeChecked(); + }); + + it('renders a "read more" link with correct href', async () => { + renderComponent(); + const group = await getGroup(); + const link = within(group).getByRole('link', { + name: /lue lisää kulttuuripoluista/i, + }); + expect(link).toHaveAttribute( + 'href', + '/fi/cms-page/kulttuurikasvatus/kulttuuripolulla-kulttuuria-kaikille' + ); + }); + + it.each([IsPartOfCulturalRoute.NO_OR_UNKNOWN, IsPartOfCulturalRoute.YES])( + 'shows no error text when submitted with valid value %p', + async (validValue) => { + renderComponent(validValue); + + await userEvent.click(screen.getByRole('button', { name: /submit/i })); + + await waitFor(() => + expect( + screen.queryByText(/tämä kenttä on pakollinen/i) + ).not.toBeInTheDocument() + ); + } + ); + + it('shows error text when the field is submitted without a selection', async () => { + renderComponent(''); + + await userEvent.click(screen.getByRole('button', { name: /submit/i })); + + await screen.findByText(/tämä kenttä on pakollinen/i); + }); +}); diff --git a/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap b/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap index b5e128fd..9ed4b96e 100644 --- a/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap +++ b/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap @@ -10,6 +10,7 @@ exports[`renders form and user can fill it and submit and form is saved to local "hasEmailNotification": true, "hasSmsNotification": false, "isMandatoryAdditionalInformationRequired": false, + "isPartOfCulturalRoute": "", "isSameResponsiblePerson": true, "isSharingDataAccepted": false, "language": "", @@ -42,6 +43,7 @@ exports[`renders form and user can fill it and submit and form is saved to local "hasEmailNotification": true, "hasSmsNotification": true, "isMandatoryAdditionalInformationRequired": true, + "isPartOfCulturalRoute": true, "isSameResponsiblePerson": true, "isSharingDataAccepted": true, "language": true, @@ -76,6 +78,7 @@ exports[`renders form and user can fill it and submit and form is saved to local "hasEmailNotification": true, "hasSmsNotification": true, "isMandatoryAdditionalInformationRequired": false, + "isPartOfCulturalRoute": "YES", "isSameResponsiblePerson": true, "isSharingDataAccepted": true, "language": "FI", @@ -112,6 +115,7 @@ exports[`renders form and user can fill it and submit and form is saved to local "hasEmailNotification": true, "hasSmsNotification": true, "isMandatoryAdditionalInformationRequired": false, + "isPartOfCulturalRoute": "YES", "isSameResponsiblePerson": true, "isSharingDataAccepted": true, "language": "FI", diff --git a/src/domain/enrolment/enrolmentForm/constants.ts b/src/domain/enrolment/enrolmentForm/constants.ts index 968b06dd..f0c32030 100644 --- a/src/domain/enrolment/enrolmentForm/constants.ts +++ b/src/domain/enrolment/enrolmentForm/constants.ts @@ -1,3 +1,8 @@ +export enum IsPartOfCulturalRoute { + NO_OR_UNKNOWN = 'NO_OR_UNKNOWN', + YES = 'YES', +} + export type EnrolmentFormFields = { hasEmailNotification: boolean; hasSmsNotification: boolean; @@ -5,6 +10,7 @@ export type EnrolmentFormFields = { isSharingDataAccepted: boolean; isMandatoryAdditionalInformationRequired: boolean; language: string; + isPartOfCulturalRoute: IsPartOfCulturalRoute | ''; person: { name: string; phoneNumber: string; @@ -34,6 +40,7 @@ export const defaultEnrolmentInitialValues: EnrolmentFormFields = { isSharingDataAccepted: false, isMandatoryAdditionalInformationRequired: false, language: '', + isPartOfCulturalRoute: '', person: { name: '', phoneNumber: '', @@ -85,4 +92,5 @@ export const nameToLabelPath: Record = { 'enrolment:enrolmentForm.studyGroup.person.labelPhoneNumber', 'person.emailAddress': 'enrolment:enrolmentForm.studyGroup.person.labelEmailAddress', + isPartOfCulturalRoute: 'enrolment:enrolmentForm.culturalRoute.labelIsPartOf', }; diff --git a/src/domain/enrolment/query.ts b/src/domain/enrolment/query.ts index 279e8f11..21bf737f 100644 --- a/src/domain/enrolment/query.ts +++ b/src/domain/enrolment/query.ts @@ -3,6 +3,7 @@ import { gql } from 'graphql-tag'; export const QUERY_ENROLMENT = gql` fragment enrolmentFields on EnrolmentNode { id + isPartOfCulturalRoute notificationType enrolmentTime status diff --git a/src/domain/enrolment/utils.ts b/src/domain/enrolment/utils.ts index 716ec139..b526f3a7 100644 --- a/src/domain/enrolment/utils.ts +++ b/src/domain/enrolment/utils.ts @@ -1,4 +1,7 @@ -import { EnrolmentFormFields } from './enrolmentForm/constants'; +import { + EnrolmentFormFields, + IsPartOfCulturalRoute, +} from './enrolmentForm/constants'; import { EnrolEventQueueMutationInput, EnrolOccurrenceMutationInput, @@ -6,6 +9,22 @@ import { NotificationType, } from '../../generated/graphql'; +/** + * Converts IsPartOfCulturalRoute.YES to true, + * IsPartOfCulturalRoute.NO_OR_UNKNOWN to false, + * and raises an error on everything else. + */ +export const validIsPartOfCulturalRouteToBoolean = ( + isPart: unknown +): boolean => { + if (isPart === IsPartOfCulturalRoute.YES) { + return true; + } else if (isPart === IsPartOfCulturalRoute.NO_OR_UNKNOWN) { + return false; + } + throw new Error(`Invalid isPartOfCulturalRoute value ${isPart}`); +}; + const getNotificationType = (values: EnrolmentFormFields): NotificationType => { return values.hasEmailNotification && values.studyGroup.person.phoneNumber && @@ -18,6 +37,9 @@ export const getEnrolmentPayloadBase = ( values: EnrolmentFormFields ): Omit => { return { + isPartOfCulturalRoute: validIsPartOfCulturalRouteToBoolean( + values.isPartOfCulturalRoute + ), notificationType: getNotificationType(values), person: values.isSameResponsiblePerson ? undefined diff --git a/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap b/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap index 72d64452..6ab00061 100644 --- a/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap +++ b/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap @@ -10,6 +10,7 @@ exports[`user can select multiple occurrences and enrol to them with enrolment f "hasEmailNotification": true, "hasSmsNotification": false, "isMandatoryAdditionalInformationRequired": false, + "isPartOfCulturalRoute": "", "isSameResponsiblePerson": true, "isSharingDataAccepted": false, "language": "FI", @@ -42,6 +43,7 @@ exports[`user can select multiple occurrences and enrol to them with enrolment f "hasEmailNotification": true, "hasSmsNotification": true, "isMandatoryAdditionalInformationRequired": true, + "isPartOfCulturalRoute": true, "isSameResponsiblePerson": true, "isSharingDataAccepted": true, "language": true, @@ -76,6 +78,7 @@ exports[`user can select multiple occurrences and enrol to them with enrolment f "hasEmailNotification": true, "hasSmsNotification": true, "isMandatoryAdditionalInformationRequired": false, + "isPartOfCulturalRoute": "NO_OR_UNKNOWN", "isSameResponsiblePerson": true, "isSharingDataAccepted": true, "language": "FI", @@ -116,6 +119,7 @@ exports[`user can select single occurrences and enrol to it with enrolment form "hasEmailNotification": true, "hasSmsNotification": false, "isMandatoryAdditionalInformationRequired": true, + "isPartOfCulturalRoute": "", "isSameResponsiblePerson": true, "isSharingDataAccepted": false, "language": "FI", @@ -148,6 +152,7 @@ exports[`user can select single occurrences and enrol to it with enrolment form "hasEmailNotification": true, "hasSmsNotification": true, "isMandatoryAdditionalInformationRequired": true, + "isPartOfCulturalRoute": true, "isSameResponsiblePerson": true, "isSharingDataAccepted": true, "language": true, @@ -182,6 +187,7 @@ exports[`user can select single occurrences and enrol to it with enrolment form "hasEmailNotification": true, "hasSmsNotification": true, "isMandatoryAdditionalInformationRequired": true, + "isPartOfCulturalRoute": "NO_OR_UNKNOWN", "isSameResponsiblePerson": true, "isSharingDataAccepted": true, "language": "FI", diff --git a/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx b/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx index de67f598..82109958 100644 --- a/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx +++ b/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx @@ -221,6 +221,7 @@ test('user can select single occurrences and enrol to it with enrolment form', a variables: { input: { captchaKey: 'captcha-token', + isPartOfCulturalRoute: false, notificationType: 'EMAIL_SMS', occurrenceIds: ['123321'], person: undefined, @@ -308,6 +309,7 @@ test('user can select multiple occurrences and enrol to them with enrolment form variables: { input: { captchaKey: 'captcha-token', + isPartOfCulturalRoute: false, notificationType: 'EMAIL_SMS', occurrenceIds: ['123321', '321123'], person: undefined, @@ -416,6 +418,15 @@ async function fillForm({ ); // close dropdown await user.click(gradeButton); + + // Answer "Is part of cultural route?" question + const culturalRouteGroup = await screen.findByRole('group', { + name: /käynti sisältyy kulttuuripolkuun/i, + }); + await userEvent.click( + within(culturalRouteGroup).getByRole('radio', { name: /ei \/ en tiedä/i }) + ); + await user.type(await enrolmentForm.findByLabelText(/lapsia/i), '10'); await user.type(await enrolmentForm.findByLabelText(/aikuisia/i), '2'); diff --git a/src/domain/eventQueueEnrolment/query.ts b/src/domain/eventQueueEnrolment/query.ts index 0fd9da23..4369551f 100644 --- a/src/domain/eventQueueEnrolment/query.ts +++ b/src/domain/eventQueueEnrolment/query.ts @@ -3,6 +3,7 @@ import { gql } from 'graphql-tag'; export const QUERY_EVENT_QUEUE_ENROLMENT = gql` fragment eventQueueEnrolmentFields on EventQueueEnrolmentNode { id + isPartOfCulturalRoute notificationType enrolmentTime status diff --git a/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx b/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx index af4a29a1..b169b0c2 100644 --- a/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx +++ b/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx @@ -3,6 +3,7 @@ import { ConfigProvider as RHHCConfigProvider, defaultConfig as rhhcDefaultConfig, } from '@city-of-helsinki/react-helsinki-headless-cms'; +import { ButtonPresetTheme, ButtonVariant } from 'hds-react'; import * as React from 'react'; import { @@ -110,8 +111,8 @@ test('renders with sidebar layout when sidebar has content', async () => { openInExternalDomainAriaLabel: 'Avautuu uudella sivustolla.', }, customCopy: { - loadMoreButtonVariant: 'primary', - loadMoreButtonTheme: 'coat', + loadMoreButtonVariant: ButtonVariant.Primary, + loadMoreButtonTheme: ButtonPresetTheme.Coat, }, internalHrefOrigins, utils: { diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx index 235e8848..1743a29a 100644 --- a/src/generated/graphql.tsx +++ b/src/generated/graphql.tsx @@ -261,6 +261,8 @@ export type EnrolEventQueueMutationInput = { /** The user response token provided by the reCAPTCHA client-side integration */ captchaKey?: InputMaybe; clientMutationId?: InputMaybe; + /** Is the enrolment part of a cultural route? False = No / I don't know, True = Yes. */ + isPartOfCulturalRoute: Scalars['Boolean']['input']; notificationType?: InputMaybe; /** The event that a group would like to queue to */ pEventId: Scalars['ID']['input']; @@ -280,6 +282,8 @@ export type EnrolOccurrenceMutationInput = { /** The user response token provided by the reCAPTCHA client-side integration */ captchaKey?: InputMaybe; clientMutationId?: InputMaybe; + /** Is the enrolment part of a cultural route? False = No / I don't know, True = Yes. */ + isPartOfCulturalRoute: Scalars['Boolean']['input']; notificationType?: InputMaybe; /** Occurrence ids of event */ occurrenceIds: Array>; @@ -302,6 +306,8 @@ export type EnrolmentNode = Node & { enrolmentTime: Scalars['DateTime']['output']; /** The ID of the object */ id: Scalars['ID']['output']; + /** Is enrolment part of a cultural route? True means yes, False means no, I don't know or unanswered. */ + isPartOfCulturalRoute: Scalars['Boolean']['output']; notificationType?: Maybe; occurrence: OccurrenceNode; person?: Maybe; @@ -411,6 +417,8 @@ export type EventQueueEnrolmentNode = Node & { enrolmentTime: Scalars['DateTime']['output']; /** The ID of the object */ id: Scalars['ID']['output']; + /** Is enrolment part of a cultural route? True means yes, False means no, I don't know or unanswered. */ + isPartOfCulturalRoute: Scalars['Boolean']['output']; notificationType?: Maybe; pEvent: PalvelutarjotinEventNode; person?: Maybe; @@ -1092,7 +1100,7 @@ export enum OrganisationTypeEnum { export enum OrganisationsOrganisationTypeChoices { /** Provider */ Provider = 'PROVIDER', - /** Käyttäjä */ + /** User */ User = 'USER' } @@ -1894,6 +1902,7 @@ export type UnpublishEventMutation = { export type UpdateEnrolmentMutationInput = { clientMutationId?: InputMaybe; enrolmentId: Scalars['ID']['input']; + isPartOfCulturalRoute?: InputMaybe; notificationType?: InputMaybe; /** Leave blank if the contact person is the same with group contact person */ person?: InputMaybe; @@ -2140,9 +2149,9 @@ export type EnrolOccurrenceMutationVariables = Exact<{ }>; -export type EnrolOccurrenceMutation = { __typename?: 'Mutation', enrolOccurrence?: { __typename?: 'EnrolOccurrenceMutationPayload', enrolments?: Array<{ __typename?: 'EnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null> | null } | null }; +export type EnrolOccurrenceMutation = { __typename?: 'Mutation', enrolOccurrence?: { __typename?: 'EnrolOccurrenceMutationPayload', enrolments?: Array<{ __typename?: 'EnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null> | null } | null }; -export type EnrolmentFieldsFragment = { __typename?: 'EnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } }; +export type EnrolmentFieldsFragment = { __typename?: 'EnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } }; export type PEventFieldsFragment = { __typename?: 'PalvelutarjotinEventNode', autoAcceptance: boolean, id: string, enrolmentEndDays?: number | null, enrolmentStart?: any | null, externalEnrolmentUrl?: string | null, neededOccurrences: number, contactPhoneNumber: string, contactEmail: string, isQueueingAllowed: boolean, mandatoryAdditionalInformation: boolean, nextOccurrenceDatetime?: any | null, lastOccurrenceDatetime?: any | null, organisation?: { __typename?: 'OrganisationNode', id: string, name: string } | null, contactPerson?: { __typename?: 'PersonNode', id: string, name: string } | null, occurrences?: { __typename?: 'OccurrenceNodeConnection', edges: Array<{ __typename?: 'OccurrenceNodeEdge', node?: { __typename?: 'OccurrenceNode', id: string, amountOfSeats: number, seatsTaken: number, seatType: OccurrencesOccurrenceSeatTypeChoices, remainingSeats: number, minGroupSize?: number | null, maxGroupSize?: number | null, cancelled: boolean, startTime: any, endTime: any, placeId: string, pEvent?: { __typename?: 'PalvelutarjotinEventNode', id: string } | null, languages: { __typename?: 'LanguageNodeConnection', edges: Array<{ __typename?: 'LanguageNodeEdge', node?: { __typename?: 'LanguageNode', id: string, name: string } | null } | null> } } | null } | null> } | null, nextOccurrence?: { __typename?: 'OccurrenceNodeConnection', edges: Array<{ __typename?: 'OccurrenceNodeEdge', node?: { __typename?: 'OccurrenceNode', id: string, startTime: any, endTime: any } | null } | null> } | null }; @@ -2166,9 +2175,9 @@ export type EnrolEventQueueMutationVariables = Exact<{ }>; -export type EnrolEventQueueMutation = { __typename?: 'Mutation', enrolEventQueue?: { __typename?: 'EnrolEventQueueMutationPayload', eventQueueEnrolment?: { __typename?: 'EventQueueEnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null } | null }; +export type EnrolEventQueueMutation = { __typename?: 'Mutation', enrolEventQueue?: { __typename?: 'EnrolEventQueueMutationPayload', eventQueueEnrolment?: { __typename?: 'EventQueueEnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null } | null }; -export type EventQueueEnrolmentFieldsFragment = { __typename?: 'EventQueueEnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } }; +export type EventQueueEnrolmentFieldsFragment = { __typename?: 'EventQueueEnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } }; export type MetaFieldsFragment = { __typename?: 'Meta', count?: number | null, next?: string | null, previous?: string | null }; @@ -2409,6 +2418,7 @@ ${PersonFieldsFragmentDoc}`; export const EnrolmentFieldsFragmentDoc = gql` fragment enrolmentFields on EnrolmentNode { id + isPartOfCulturalRoute notificationType enrolmentTime status @@ -2633,6 +2643,7 @@ ${VenueFieldsFragmentDoc}`; export const EventQueueEnrolmentFieldsFragmentDoc = gql` fragment eventQueueEnrolmentFields on EventQueueEnrolmentNode { id + isPartOfCulturalRoute notificationType enrolmentTime status diff --git a/src/playwright/mocks.ts b/src/playwright/mocks.ts index cdb5aab3..f108a1fb 100644 --- a/src/playwright/mocks.ts +++ b/src/playwright/mocks.ts @@ -412,6 +412,7 @@ export const MOCK_ENROL_OCCURRENCE_MUTATION_RESPONSE: EnrolOccurrenceMutation = enrolments: [ { id: 'RW5yb2xtZW50Tm9kZTo5ODI=', + isPartOfCulturalRoute: true, notificationType: NotificationType.Email, enrolmentTime: '2025-05-06T10:49:07.076077+00:00', status: EnrolmentStatus.Pending, diff --git a/src/playwright/pages/event.page.ts b/src/playwright/pages/event.page.ts index 1c6b7810..ae5aa6ec 100644 --- a/src/playwright/pages/event.page.ts +++ b/src/playwright/pages/event.page.ts @@ -48,11 +48,21 @@ const TRANS = { sv: /^Grupp \*/, en: /^Group name \*/, }, + isPartOfCulturalRoute: { + fi: /^Käynti sisältyy kulttuuripolkuun \*/, + sv: /^Besöket ingår i kulturstigen \*/, + en: /^The visit is part of the cultural route \*/, + }, name: { fi: /^Nimi \*/, sv: /^Namn \*/, en: /^Name \*/, }, + noOrUnknown: { + fi: 'Ei / en tiedä', + sv: 'Nej / jag vet inte', + en: "No / I don't know", + }, phoneNumber: { fi: 'Puhelinnumero *', sv: 'Telefonnummer *', @@ -98,6 +108,11 @@ const TRANS = { sv: 'Skicka anmälan', en: 'Submit enquiry', }, + yes: { + fi: 'Kyllä', + sv: 'Ja', + en: 'Yes', + }, } as const satisfies Record; type TranslationsOf = @@ -247,6 +262,23 @@ export class EventPage extends BasePage { await this.hasVisibleHeading(TRANS.reservationEnquirySent[lang]); } + /** + * Select a radio button answer to "Is part of cultural route?" question. + * @param lang Language + * @param value False to select "No / I don't know", true to select "Yes". + */ + async selectIsPartOfCulturalRoute(lang: Language, value: boolean) { + const isPartOfCulturalRouteGroup = this.enrolmentForm.getByRole('group', { + name: TRANS.isPartOfCulturalRoute[lang], + }); + const radioButtonName = value ? TRANS.yes[lang] : TRANS.noOrUnknown[lang]; + const radioButtonLabel = isPartOfCulturalRouteGroup.getByText( + radioButtonName, + { exact: true } + ); + await radioButtonLabel.click(); + } + /** * Wait for study group unit list to load with at least a single option. */ diff --git a/src/playwright/pages/searchCapable.page.ts b/src/playwright/pages/searchCapable.page.ts index 3c1603a9..b4baf2f3 100644 --- a/src/playwright/pages/searchCapable.page.ts +++ b/src/playwright/pages/searchCapable.page.ts @@ -7,7 +7,10 @@ type ZeroToTwoYears = '0-2 vuotiaat' | '0-2 år' | '0-2 years'; type TargetGroupOption = ZeroToTwoYears; type SearchOption = TargetGroupOption; type SearchEvents = 'Hae tapahtumia' | 'Sök evenemang' | 'Search events'; -type AdvancedSearch = 'Tarkennettu haku' | 'Redigera sökning' | 'Edit search'; +type AdvancedSearch = + | 'Tarkennettu haku' + | 'Detaljerad sökning' + | 'Advanced search'; type SearchButton = SearchEvents | AdvancedSearch; type SearchTextBox = SearchEvents | TargetGroupButton; type TargetGroupField = TargetGroupButton; diff --git a/src/playwright/tests/eventEnrolling.spec.ts b/src/playwright/tests/eventEnrolling.spec.ts index 361a0527..1cbef66a 100644 --- a/src/playwright/tests/eventEnrolling.spec.ts +++ b/src/playwright/tests/eventEnrolling.spec.ts @@ -28,6 +28,7 @@ LANGUAGES.forEach((lang) => { await eventPage.selectDaycareKamppiForStudyGroupUnit(lang); await eventPage.fillStudyGroupName(lang, 'Testiryhmä'); await eventPage.selectPreschoolForStudyLevel(lang); + await eventPage.selectIsPartOfCulturalRoute(lang, true); await eventPage.selectNumberOfChildren(lang, '8'); await eventPage.selectNumberOfAdults(lang, '2'); await eventPage.fillAdditionalInfo(lang, 'Neurokirjon ryhmä'); diff --git a/src/utils/mockDataUtils.ts b/src/utils/mockDataUtils.ts index d8af54c4..3fe3a592 100644 --- a/src/utils/mockDataUtils.ts +++ b/src/utils/mockDataUtils.ts @@ -155,6 +155,7 @@ export const fakeEnrolments = ( export const fakeEnrolment = ( overrides?: Partial ): EnrolmentNode => ({ + isPartOfCulturalRoute: faker.datatype.boolean(), enrolmentTime: '2020-08-18T06:37:40.755109+00:00', updatedAt: '2020-08-18T06:37:40.755109+00:00', id: faker.string.uuid(),