-
Notifications
You must be signed in to change notification settings - Fork 112
(test) O3-4968: Adding e2e tests for TranslationBuilder component #833
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
base: main
Are you sure you want to change the base?
Changes from all commits
ef2959e
f6514ea
3be06ac
2bec8c3
ed1dfe7
90abacd
977c97f
f93ebdc
95d0bd9
fae2941
dee15b2
4b007ba
833dfdc
7090561
49fe191
2581cb8
9f73bc6
5bf32e7
03cf72e
e9871f9
4d2d42e
cd025b2
04820c4
76adcd2
78a81e4
6891076
96485a8
8eec6a6
fbbed14
b1af41d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| import { test } from '../core'; | ||
| import { expect } from '@playwright/test'; | ||
| import { deleteForm, createForm, createValueReference, addFormResources } from '../commands/form-operations'; | ||
| import { FormBuilderPage } from '../pages'; | ||
|
|
||
| let formUuid = ''; | ||
|
|
||
| const formDetails = { | ||
| name: 'Covid-19 Screening', | ||
| description: 'A test form for recording COVID-19 screening information', | ||
| version: '1.0', | ||
| published: true, | ||
| }; | ||
| test.describe('Translation Builder', () => { | ||
| test.beforeEach(async ({ api }) => { | ||
| const form = await createForm(api, false, formDetails); | ||
| formUuid = form.uuid; | ||
|
|
||
| const valueReference = await createValueReference(api); | ||
| await addFormResources(api, valueReference, formUuid); | ||
| }); | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| test('Manage translations: switch languages, filter, and search', async ({ page }) => { | ||
| const formBuilderPage = new FormBuilderPage(page); | ||
|
|
||
| await test.step('When I open a form in the translation builder', async () => { | ||
| await formBuilderPage.gotoFormBuilder(); | ||
| await formBuilderPage.searchForForm(formDetails.name); | ||
| await formBuilderPage.page.getByRole('row', { name: formDetails.name }).getByLabel('Edit Schema').first().click(); | ||
| await formBuilderPage.translationBuilderTab().click(); | ||
| }); | ||
|
|
||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await test.step('When I open the language dropdown', async () => { | ||
| await formBuilderPage.languageDropdown().click(); | ||
| }); | ||
|
|
||
| await test.step('Then I should see the language list', async () => { | ||
| const dropdownMenu = formBuilderPage.translationBuilderPanel().locator('.cds--list-box__menu'); | ||
| await expect(dropdownMenu).toBeVisible(); | ||
| }); | ||
|
|
||
| await test.step('And I should see "English (en)" in the language list', async () => { | ||
| await expect(formBuilderPage.page.getByRole('option', { name: 'English (en)' })).toBeVisible(); | ||
| }); | ||
|
|
||
| await test.step('When I select the "All" translations tab', async () => { | ||
| await formBuilderPage.allTranslationsTab().click(); | ||
| }); | ||
|
|
||
| await test.step('Then the "All" translations tab should be selected', async () => { | ||
| await expect(formBuilderPage.allTranslationsTab()).toHaveAttribute('aria-selected', 'true'); | ||
| }); | ||
|
|
||
| await test.step('When I select the "Translated" translations tab', async () => { | ||
| await formBuilderPage.translatedTab().click(); | ||
| }); | ||
|
|
||
| await test.step('Then I should see 0 "translated" entries', async () => { | ||
| await expect(page.locator('[data-status="translated"]')).toHaveCount(0); | ||
| }); | ||
|
|
||
| await test.step('When I select the "Untranslated" translations tab', async () => { | ||
| await formBuilderPage.untranslatedTab().click(); | ||
| }); | ||
|
|
||
| await test.step('Then the "Untranslated" translations tab should be selected', async () => { | ||
| await expect(formBuilderPage.untranslatedTab()).toHaveAttribute('aria-selected', 'true'); | ||
| }); | ||
|
|
||
| await test.step('And I should see at least 1 "untranslated" entry', async () => { | ||
| await expect(page.locator('[data-status="untranslated"]').first()).toBeVisible(); | ||
| }); | ||
|
|
||
| await test.step('When I search translations for "Visit Details"', async () => { | ||
| const searchInput = formBuilderPage.translationSearchInput(); | ||
| await searchInput.fill('Visit Details'); | ||
| }); | ||
|
|
||
| await test.step('Then the translation search input should contain "Visit Details"', async () => { | ||
| const searchInput = formBuilderPage.translationSearchInput(); | ||
| await expect(searchInput).toHaveValue('Visit Details'); | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }); | ||
|
|
||
| await test.step('And I should see at least 1 translation result', async () => { | ||
| const results = page.locator('[data-testid="translation-entry"]'); | ||
| await expect(results).not.toHaveCount(0); | ||
| }); | ||
|
|
||
| await test.step('And the first translation result should be visible', async () => { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Shouldn't this include that the translation result should contain the word |
||
| const results = page.locator('[data-testid="translation-entry"]'); | ||
| await expect(results.first()).toBeVisible(); | ||
| }); | ||
| }); | ||
|
|
||
| test('Edit and update an individual translation', async ({ page }) => { | ||
| const formBuilderPage = new FormBuilderPage(page); | ||
|
|
||
| await test.step('When I open a form in the Translation Builder', async () => { | ||
| await formBuilderPage.gotoFormBuilder(); | ||
| await formBuilderPage.searchForForm(formDetails.name); | ||
| await formBuilderPage.page.getByRole('row', { name: formDetails.name }).getByLabel('Edit Schema').first().click(); | ||
| }); | ||
|
|
||
| await test.step('And then I go to the translation builder', async () => { | ||
| await formBuilderPage.translationBuilderTab().click(); | ||
| }); | ||
|
|
||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await test.step('And then I select the French language', async () => { | ||
| await formBuilderPage.languageDropdown().click(); | ||
| const dropdownMenu = formBuilderPage.translationBuilderPanel().locator('.cds--list-box__menu'); | ||
| await expect(dropdownMenu).toBeVisible(); | ||
| await formBuilderPage.page.getByRole('option', { name: 'French (fr)' }).click(); | ||
| }); | ||
|
|
||
| await test.step('And then I edit a translation string and save it', async () => { | ||
| await formBuilderPage.editTranslationButton(0).click(); | ||
| const translationInput = formBuilderPage.translationValueInput(); | ||
| await translationInput.fill('Test Translation Updated'); | ||
| }); | ||
| await test.step('And then when I preview the form in the language, I should see the edited translation strings', async () => { | ||
| await formBuilderPage.saveTranslationButton().click(); | ||
| await expect(formBuilderPage.translationModal()).toBeHidden(); | ||
| await expect(formBuilderPage.editTranslationButton(0)).toBeEnabled(); | ||
| }); | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }); | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| test('Download a translation file from a form', async ({ page }) => { | ||
| const formBuilderPage = new FormBuilderPage(page); | ||
|
|
||
| await test.step('Given I have opened a form in the Form Builder', async () => { | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await formBuilderPage.gotoFormBuilder(); | ||
| await formBuilderPage.searchForForm(formDetails.name); | ||
| await formBuilderPage.page.getByRole('row', { name: formDetails.name }).getByLabel('Edit Schema').first().click(); | ||
| }); | ||
|
|
||
| await test.step('When I navigate to the Translation Builder', async () => { | ||
| await formBuilderPage.translationBuilderTab().click(); | ||
| }); | ||
|
|
||
| await test.step('Then I should be able to download the translation file', async () => { | ||
| const downloadButton = formBuilderPage.downloadTranslationButton(); | ||
| const [download] = await Promise.all([ | ||
| formBuilderPage.page.waitForEvent('download', { timeout: 15000 }), | ||
| downloadButton.click(), | ||
| ]); | ||
| expect(download.suggestedFilename()).toMatch(/\.json$/); | ||
| }); | ||
| }); | ||
|
|
||
| test('Upload a translation file to backend', async ({ page }) => { | ||
| const formBuilderPage = new FormBuilderPage(page); | ||
|
|
||
| await test.step('Given I have opened a form in the Form Builder', async () => { | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await formBuilderPage.gotoFormBuilder(); | ||
| await formBuilderPage.searchForForm(formDetails.name); | ||
| await formBuilderPage.page.getByRole('row', { name: formDetails.name }).getByLabel('Edit Schema').first().click(); | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }); | ||
|
|
||
| await test.step('When I navigate to the Translation Builder', async () => { | ||
| await formBuilderPage.translationBuilderTab().click(); | ||
| }); | ||
|
|
||
| await test.step('Then I should be able to upload a translation file successfully', async () => { | ||
| const uploadButton = formBuilderPage.uploadTranslationButton(); | ||
| await expect(uploadButton).toBeEnabled(); | ||
| await expect(uploadButton).toBeVisible(); | ||
| await expect(formBuilderPage.translationBuilderPanel()).toBeVisible(); | ||
|
|
||
| await uploadButton.click(); | ||
| await expect(formBuilderPage.page.getByText(/Translations Uploaded./i)).toBeVisible(); | ||
| await expect(formBuilderPage.page.getByText(/Translation file uploaded successfully/i)).toBeVisible(); | ||
| }); | ||
| }); | ||
|
|
||
| test.afterEach(async ({ api }) => { | ||
| if (formUuid) { | ||
| await deleteForm(api, formUuid); | ||
| } | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ const EditTranslationModal: React.FC<EditTranslationModalProps> = ({ onClose, or | |
| labelText={t('translationValue', 'Translated Value')} | ||
| value={newValue} | ||
| onChange={(e) => setNewValue(e.target.value)} | ||
| data-testid="translation-value-input" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: Is the data test id necessary? Can't we target the button from the label text? |
||
| /> | ||
| </ModalBody> | ||
| <ModalFooter> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -223,21 +223,22 @@ const TranslationBuilder: React.FC<TranslationBuilderProps> = ({ formSchema, onU | |
| onChange={({ selectedItem }) => selectedItem && languageChanger(selectedItem.code)} | ||
| /> | ||
| </div> | ||
|
|
||
| <div className={styles.translationActions}> | ||
| <button className={styles.linkButton} onClick={handleDownloadTranslation}> | ||
| {t('downloadTranslation', 'Download translation')} | ||
| <Download size={16} /> | ||
| </button> | ||
| <button | ||
| className={styles.linkButton} | ||
| onClick={handleUploadTranslationFromSchema} | ||
| disabled={translationsUploading} | ||
| > | ||
| {t('uploadTranslation', 'Upload translation')} | ||
| {!translationsUploading ? <Upload size={16} /> : <InlineLoading />} | ||
| </button> | ||
| </div> | ||
| {formSchema ? ( | ||
| <div className={styles.translationActions}> | ||
| <button className={styles.linkButton} onClick={handleDownloadTranslation}> | ||
| {t('downloadTranslation', 'Download translation')} | ||
| <Download size={16} /> | ||
| </button> | ||
| <button | ||
| className={styles.linkButton} | ||
| onClick={handleUploadTranslationFromSchema} | ||
| disabled={translationsUploading} | ||
| > | ||
| {t('uploadTranslation', 'Upload translation')} | ||
| {!translationsUploading ? <Upload size={16} /> : <InlineLoading />} | ||
| </button> | ||
| </div> | ||
| ) : null} | ||
Bharath-K-Shetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </div> | ||
|
|
||
| <div className={styles.translationTabs}> | ||
|
|
@@ -287,16 +288,26 @@ const TranslationBuilder: React.FC<TranslationBuilderProps> = ({ formSchema, onU | |
| <div className={styles.translationEditor}> | ||
| {filteredTranslations.length > 0 ? ( | ||
| filteredTranslations.map(([key, value]) => ( | ||
| <div key={key} className={styles.translationRow}> | ||
| <div className={styles.translationKey}>{key}</div> | ||
| <div className={styles.translatedKey}>{value}</div> | ||
| <div | ||
| key={key} | ||
| className={styles.translationRow} | ||
| data-testid="translation-entry" | ||
| data-status="untranslated" | ||
| > | ||
| <div className={styles.translationKey} data-testid="translation-key"> | ||
| {key} | ||
| </div> | ||
| <div className={styles.translatedKey} data-testid="translation-value"> | ||
| {value} | ||
| </div> | ||
| <div className={styles.inlineControls}> | ||
| <IconButton | ||
| kind="ghost" | ||
| label={t('editString', 'Edit string')} | ||
| onClick={() => handleEditClick(key)} | ||
| size="md" | ||
| className={styles.deleteButton} | ||
| data-testid="edit-translation-button" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question here about the label |
||
| > | ||
| <Edit /> | ||
| </IconButton> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.