diff --git a/.github/workflows/integration-testing.yaml b/.github/workflows/integration-testing.yaml index 73c16e5a3e..887dd2f73f 100644 --- a/.github/workflows/integration-testing.yaml +++ b/.github/workflows/integration-testing.yaml @@ -2,12 +2,13 @@ name: Run Integration Tests on: merge_group: pull_request: + workflow_dispatch: concurrency: integration_environment jobs: variables: - if: ${{ github.event_name == 'merge_group' }} + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest outputs: date: ${{ steps.data.outputs.date }} @@ -28,7 +29,7 @@ jobs: echo "current_branch=merge-queue" >> $GITHUB_OUTPUT build-generic: - if: ${{ github.event_name == 'merge_group' }} + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} name: "Integration Image Build" needs: - variables @@ -82,7 +83,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-derived: - if: ${{ github.event_name == 'merge_group' }} + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest name: "Integration Image Build Stage 2" permissions: @@ -139,7 +140,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} run-tests: - if: ${{ github.event_name == 'merge_group' }} + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} name: "Playwright" # This name is referenced when slacking status needs: - build-derived @@ -203,7 +204,7 @@ jobs: - name: Uninstall run: helm delete integration-${{ needs.variables.outputs.commit }} -n ${{ secrets.DEV_SANDBOX_NAMESPACE }} --debug --timeout 10m0s ending-notification: - if: ${{ github.event_name == 'merge_group' }} + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest needs: - run-tests diff --git a/e2e-tests/globals.ts b/e2e-tests/globals.ts index a4b53698f2..03dd92ca82 100644 --- a/e2e-tests/globals.ts +++ b/e2e-tests/globals.ts @@ -5,6 +5,12 @@ export const LANGUAGES = { 'HE': 'hebrew', } +export const SOURCE_LANGUAGES = { + 'EN': 'div.toggleOption.english', + 'HE': 'div.toggleOption.hebrew', + 'BI': 'div.toggleOption.bilingual' +} + export const cookieObject = { "name": "interfaceLang", "value": DEFAULT_LANGUAGE, diff --git a/e2e-tests/tests/interface-language-is-sticky.spec.ts b/e2e-tests/tests/interface-language-is-sticky.spec.ts new file mode 100644 index 0000000000..9312d18409 --- /dev/null +++ b/e2e-tests/tests/interface-language-is-sticky.spec.ts @@ -0,0 +1,69 @@ +import {test, expect} from '@playwright/test'; +import {goToPageWithLang, isIsraelIp} from "../utils"; +import {LANGUAGES, SOURCE_LANGUAGES} from '../globals' + +const interfaceTextHE = 'מקורות'; +const interfaceTextEN = 'Texts'; + +[ + // Hebrew Interface and English Source + {interfaceLanguage: 'Hebrew', interfaceLanguageToggle: LANGUAGES.HE, + sourceLanguage: 'English', sourceLanguageToggle: SOURCE_LANGUAGES.EN, + expectedSourceText: 'When God began to create', expectedBilingualText: '', expectedInterfaceText: interfaceTextHE }, + + // Hebrew Interface and Bilingual Source + {interfaceLanguage: 'Hebrew', interfaceLanguageToggle: LANGUAGES.HE, + sourceLanguage: 'Bilingual', sourceLanguageToggle: SOURCE_LANGUAGES.BI, + expectedSourceText: 'רֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃', expectedBilingualText: 'When God began to create', expectedInterfaceText: interfaceTextHE }, + + // Hebrew Interface and Hebrew Source + {interfaceLanguage: 'Hebrew', interfaceLanguageToggle: LANGUAGES.HE, + sourceLanguage: 'Hebrew', sourceLanguageToggle: SOURCE_LANGUAGES.HE, + expectedSourceText: 'רֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃', expectedBilingualText: '', expectedInterfaceText: interfaceTextHE }, + + // English Interface and English Source + {interfaceLanguage: 'English', interfaceLanguageToggle: LANGUAGES.EN, + sourceLanguage: 'English', sourceLanguageToggle: SOURCE_LANGUAGES.EN, + expectedSourceText: 'When God began to create', expectedBilingualText: '', expectedInterfaceText: interfaceTextEN }, + + // English Interface and Bilingual Source + {interfaceLanguage: 'English', sinterfaceLanguageToggle: LANGUAGES.EN, + sourceLanguage: 'Bilingual', sourceLanguageToggle: SOURCE_LANGUAGES.BI, + expectedSourceText: 'רֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃', expectedBilingualText: 'When God began to create', + expectedInterfaceText: interfaceTextEN }, + + // English Interface and Hebrew Source + {interfaceLanguage: 'English', interfaceLanguageToggle: LANGUAGES.EN, + sourceLanguage: 'Hebrew', sourceLanguageToggle: SOURCE_LANGUAGES.HE, + expectedSourceText: 'רֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃', expectedBilingualText: '', expectedInterfaceText: interfaceTextEN } + +].forEach(({interfaceLanguage, interfaceLanguageToggle, sourceLanguage, sourceLanguageToggle, expectedSourceText, expectedBilingualText, expectedInterfaceText}) => { + test(`${interfaceLanguage} Interface Language with ${sourceLanguage} Source`, async ({ context }) => { + + // Navigating to Bereshit with selected Interface Language, Hebrew or English + const page = await goToPageWithLang(context,'/Genesis.1',`${interfaceLanguageToggle}`) + + // Clicking on the Source Language toggle + await page.getByAltText('Toggle Reader Menu Display Settings').click() + + // Selecting Source Language + await page.getByRole('radiogroup', {name: 'Language'}).locator(`${sourceLanguageToggle}`).click() + + // Locating the source text segment, then verifying translation + await expect(page.locator('div.segmentNumber').first().locator('..').locator('p')).toContainText(`${expectedSourceText}`) + + // Checking out the second part of the text, if 'Bilingual' is selected + if(`${sourceLanguage}` === 'Bilingual'){ + await expect(page.locator('div.segmentNumber').first().locator('..').locator('p span').last()).toContainText(`${expectedBilingualText}`) + const isIL = await isIsraelIp(page); + if (isIL) { + expectedInterfaceText = interfaceTextHE; + } + } + + // Validate Hebrew interface language is still toggled + const textLink = page.locator('a.textLink').first() + await expect(textLink).toHaveText(`${expectedInterfaceText}`) + + }) +}) \ No newline at end of file diff --git a/e2e-tests/tests/translation-version-name-appears-in-title.spec.ts b/e2e-tests/tests/translation-version-name-appears-in-title.spec.ts new file mode 100644 index 0000000000..5e726eb87a --- /dev/null +++ b/e2e-tests/tests/translation-version-name-appears-in-title.spec.ts @@ -0,0 +1,80 @@ +import {test, expect} from '@playwright/test'; +import {goToPageWithLang, changeLanguageOfText} from "../utils"; +import {LANGUAGES, SOURCE_LANGUAGES} from '../globals' + +[ + // Hebrew Interface and Hebrew Source + {interfaceLanguage: 'Hebrew', interfaceLanguageToggle: LANGUAGES.HE, + sourceLanguage: 'Hebrew', sourceLanguageToggle: SOURCE_LANGUAGES.HE, + translations: 'תרגומים', select: 'בחירה', currentlySelected: 'נוכחי'}, + + // Hebrew Interface and Bilingual Source + {interfaceLanguage: 'Hebrew', interfaceLanguageToggle: LANGUAGES.HE, + sourceLanguage: 'Bilingual', sourceLanguageToggle: SOURCE_LANGUAGES.BI, + translations: 'תרגומים', select: 'בחירה', currentlySelected: 'נוכחי'}, + + // Hebrew Interface and English Source + {interfaceLanguage: 'Hebrew', interfaceLanguageToggle: LANGUAGES.HE, + sourceLanguage: 'English', sourceLanguageToggle: SOURCE_LANGUAGES.EN, + translations: 'תרגומים', select: 'בחירה', currentlySelected: 'נוכחי'}, + + // English Interface and English Source + {interfaceLanguage: 'English', interfaceLanguageToggle: LANGUAGES.EN, + sourceLanguage: 'English', sourceLanguageToggle: SOURCE_LANGUAGES.EN, + translations: 'Translations', select: 'Select', currentlySelected: 'Currently Selected'}, + + // English Interface and English Source + {interfaceLanguage: 'English', interfaceLanguageToggle: LANGUAGES.EN, + sourceLanguage: 'Bilingual', sourceLanguageToggle: SOURCE_LANGUAGES.BI, + translations: 'Translations', select: 'Select', currentlySelected: 'Currently Selected'}, + + // English Interface and Hebrew Source + {interfaceLanguage: 'English', interfaceLanguageToggle: LANGUAGES.EN, + sourceLanguage: 'Hebrew', sourceLanguageToggle: SOURCE_LANGUAGES.HE, + translations: 'Translations', select: 'Select', currentlySelected: 'Currently Selected'} + +].forEach(({interfaceLanguage, interfaceLanguageToggle, sourceLanguage, sourceLanguageToggle, translations, currentlySelected, select}) => { + test(`${interfaceLanguage} - translation name appears in title for ${sourceLanguage} source text`, async ({ context }) => { + // Navigate to Bereshit in specified Interface Language + const page = await goToPageWithLang(context,'/Genesis.1', `${interfaceLanguageToggle}`) + + // Change the Source Language of the text + await changeLanguageOfText(page, `${sourceLanguageToggle}`) + + // Retain the translation name locator + const translationNameInTitle = page.locator('span.readerTextVersion') + + // Navigate to the Translations sidebar by clicking on the text title + //Clicks on בראשית א׳ / Genesis I + await page.locator('h1').click() + + // Click on Translations + await page.getByRole('link', {name: `${translations}`}).click() + + // Wait for Translations side-bar to load by waiting for 'Translations' header + await page.waitForSelector('h3') + + // Check if the default translation in the title matches the selected translation + // NOTE: We are skipping checking for the default translation here, due to the Hebrew text being default Masoretic + if(sourceLanguage !== 'Hebrew'){ + const defaultTranslation = await translationNameInTitle.textContent() + await expect(page.locator('div.version-with-preview-title-line', {hasText: defaultTranslation!}).getByRole('link')).toHaveText(`${currentlySelected}`) + } + + // TODO: 4th translation, handling Hebrew Interface translations in Hebrew. For example: 'חומש רש״י, רבי שרגא זילברשטיין' should appear in the translation title as written. + const translationNames = ['The Schocken Bible, Everett Fox, 1995 ©', '«Да» project'] + + // Utilizing the traditional for-loop as there are async issues with foreach + for(let i = 0; i < translationNames.length; i++){ + + // "Select" another translation. + await page.locator('div.version-with-preview-title-line', {hasText: translationNames[i]}).getByText(`${select}`).click() + + // Validate selected translation is reflected in title + await expect(translationNameInTitle).toHaveText(translationNames[i]) + + // Validate selected translation says 'Currently Selected' + await expect(page.locator('div.version-with-preview-title-line', {hasText: translationNames[i]}).getByRole('link')).toHaveText(`${currentlySelected}`) + } + }) +}); \ No newline at end of file diff --git a/e2e-tests/utils.ts b/e2e-tests/utils.ts index dc3922d64e..8a6a362e49 100644 --- a/e2e-tests/utils.ts +++ b/e2e-tests/utils.ts @@ -1,4 +1,4 @@ -import {DEFAULT_LANGUAGE, LANGUAGES, testUser} from './globals' +import {DEFAULT_LANGUAGE, LANGUAGES, SOURCE_LANGUAGES, testUser} from './globals' import {BrowserContext} from 'playwright-core'; import type { Page } from 'playwright-core'; @@ -23,13 +23,16 @@ export const changeLanguage = async (page: Page, language: string) => { } export const goToPageWithLang = async (context: BrowserContext, url: string, language=DEFAULT_LANGUAGE) => { - if (!langCookies.length) { - const page: Page = await context.newPage(); - await page.goto(''); - await changeLanguage(page, language); - langCookies = await context.cookies(); - } + // If a cookie already has contents, clear it so that the language cookie can be reset + if (langCookies.length) { + await context.clearCookies() + } + const page: Page = await context.newPage(); + await page.goto(''); + await changeLanguage(page, language); + langCookies = await context.cookies(); await context.addCookies(langCookies); + // this is a hack to get the cookie to work const newPage: Page = await context.newPage(); await newPage.goto(url); @@ -65,4 +68,27 @@ export const goToPageWithUser = async (context: BrowserContext, url: string, use export const getPathAndParams = (url: string) => { const urlObj = new URL(url); return urlObj.pathname + urlObj.search; +} + +export const changeLanguageOfText = async (page: Page, sourceLanguage: string) => { + // Clicking on the Source Language toggle + await page.getByAltText('Toggle Reader Menu Display Settings').click() + + // Selecting Source Language + await page.getByRole('radiogroup', {name: 'Language'}).locator(sourceLanguage).click() + +} + +export const getCountryByIp = async (page: Page) => { + const data = await page.evaluate(() => { + return fetch('https://ipapi.co/json/') + .then(response => response.json()) + .then(data => data) + }) + return data.country; +} + +export const isIsraelIp = async (page: Page) => { + const country = await getCountryByIp(page); + return country === "IL"; } \ No newline at end of file