Skip to content

Commit

Permalink
Merge branch 'development' of github.com:epam/ai-dial-chat into e2e/e…
Browse files Browse the repository at this point in the history
…rrors_on_stop_button_tests

# Conflicts:
#	e2e/src/testData/expectedMessages.ts
#	e2e/src/tests/chatBarFolderConversation.test.ts
#	e2e/src/tests/workWithModels.test.ts
#	e2e/src/ui/webElements/dropdownMenu.ts
#	e2e/src/ui/webElements/folders.ts
  • Loading branch information
irinakartun committed Dec 18, 2023
2 parents 2871f1a + facf284 commit 7af7df5
Show file tree
Hide file tree
Showing 86 changed files with 2,392 additions and 525 deletions.
11 changes: 9 additions & 2 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,41 @@ AUTH_AUTH0_CLIENT_ID=""
AUTH_AUTH0_HOST=""
AUTH_AUTH0_NAME=""
AUTH_AUTH0_SECRET=""
AUTH_AUTH0_SCOPE=""

### Azure AD
AUTH_AZURE_AD_CLIENT_ID=""
AUTH_AZURE_AD_NAME=""
AUTH_AZURE_AD_SECRET=""
AUTH_AZURE_AD_TENANT_ID=""
AUTH_AZURE_AD_SCOPE=""

### Gitlab
AUTH_GITLAB_CLIENT_ID=""
AUTH_GITLAB_HOST=""
AUTH_GITLAB_NAME=""
AUTH_GITLAB_SECRET=""
AUTH_GITLAB_SCOPE=""

### Google
AUTH_GOOGLE_CLIENT_ID=""
AUTH_GOOGLE_NAME=""
AUTH_GOOGLE_SECRET=""
AUTH_GOOGLE_SCOPE=""

### Keykloak
AUTH_KEYCLOAK_CLIENT_ID=""
AUTH_KEYCLOAK_HOST=""
AUTH_KEYCLOAK_NAME=""
AUTH_KEYCLOAK_SECRET=""
AUTH_KEYCLOAK_SCOPE=""

### PingID
AUTH_PING_ID_CLIENT_ID=""
AUTH_PING_ID_HOST=""
AUTH_PING_ID_NAME=""
AUTH_PING_ID_SECRET=""
AUTH_PING_ID_SCOPE=""

### Credentials
AUTH_TEST_TOKEN="TEST"
Expand All @@ -59,7 +65,7 @@ IS_IFRAME="false"


# Application UI settings
ENABLED_FEATURES="conversations-section,prompts-section,top-settings,top-clear-conversation,top-chat-info,top-chat-model-settings,empty-chat-settings,header,footer,request-api-key,report-an-issue,likes,conversations-sharing,prompts-sharing,input-files,attachments-manager"
ENABLED_FEATURES="conversations-section,prompts-section,top-settings,top-clear-conversation,top-chat-info,top-chat-model-settings,empty-chat-settings,header,footer,request-api-key,report-an-issue,likes,conversations-sharing,prompts-sharing,input-files,attachments-manager,conversations-publishing,prompts-publishing"
NEXT_PUBLIC_APP_NAME="Local Development APP Name"
NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=""
NEXT_PUBLIC_DEFAULT_TEMPERATURE="1"
Expand All @@ -70,7 +76,8 @@ RECENT_ADDONS_IDS="addon-epam10k-golden-qna,addon-epam10k-semantic-search,addon-

# E2E
E2E_HOST="http://localhost:3000"
PREVIEW_TEST_TOKEN="TEST" # this should be same as AUTH_TEST_TOKEN for correct E2E login
E2E_USERNAME="" # used for Auth0 E2E login
E2E_PASSWORD=""
TRACES_URL=""
TMS_URL=""
ISSUE_URL=""
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,22 +157,28 @@ Also we have a lot of auth specific env variables:
| `AUTH_AUTH0_HOST` | No | Auth0 Host | Any string | |
| `AUTH_AUTH0_NAME` | No | Auth0 Name | Any string | |
| `AUTH_AUTH0_SECRET` | No | Auth0 Secret | Any string | |
| `AUTH_AUTH0_SCOPE` | No | Auth0 Scope | Any string | `openid email profile offline_access` |
| `AUTH_AZURE_AD_CLIENT_ID` | No | Azure AD Client ID | Any string | |
| `AUTH_AZURE_AD_NAME` | No | Azure AD Name | Any string | |
| `AUTH_AZURE_AD_SECRET` | No | Azure AD Secret | Any string | |
| `AUTH_AZURE_AD_TENANT_ID` | No | Azure AD Tenant ID | Any string | |
| `AUTH_AZURE_AD_SCOPE` | No | Azure AD Scope | Any string | `openid profile user.Read email offline_access` |
| `AUTH_GITLAB_CLIENT_ID` | No | GitLab Client ID | Any string | |
| `AUTH_GITLAB_HOST` | No | GitLab Host | Any string | |
| `AUTH_GITLAB_NAME` | No | GitLab Name | Any string | |
| `AUTH_GITLAB_SECRET` | No | GitLab Secret | Any string | |
| `AUTH_GITLAB_SCOPE` | No | GitLab Scope | Any string | `read_user` |
| `AUTH_GOOGLE_CLIENT_ID` | No | Google Client ID | Any string | |
| `AUTH_GOOGLE_NAME` | No | Google Name | Any string | |
| `AUTH_GOOGLE_SECRET` | No | Google Secret | Any string | |
| `AUTH_GOOGLE_SCOPE` | No | Google Scope | Any string | `openid email profile offline_access` |
| `AUTH_KEYCLOAK_CLIENT_ID` | No | Keycloak Client ID | Any string | |
| `AUTH_KEYCLOAK_HOST` | No | Keycloak Host | Any string | |
| `AUTH_KEYCLOAK_NAME` | No | Keycloak Name | Any string | |
| `AUTH_KEYCLOAK_SECRET` | No | Keycloak Secret | Any string | |
| `AUTH_KEYCLOAK_SCOPE` | No | Keycloak Scope | Any string | `openid email profile offline_access` |
| `AUTH_PING_ID_CLIENT_ID` | No | PingID Client ID | Any string | |
| `AUTH_PING_ID_HOST` | No | PingID Host | Any string | |
| `AUTH_PING_ID_NAME` | No | PingID Name | Any string | |
| `AUTH_PING_ID_SECRET` | No | PingID Secret | Any string | |
| `AUTH_PING_ID_SCOPE` | No | PingID Scope | Any string | `offline_access` |
2 changes: 1 addition & 1 deletion e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The package contains Dial end-to-end tests. Tests are implemented using [Playwri
Tests are using Auth0 credentials to access an application.
Please, set `AUTH_TEST_TOKEN` variable in .env file in order to enable it.

When run tests on CI, `PREVIEW_TEST_TOKEN` CI variable should be set.
When run tests on CI, `E2E_USERNAME` and `E2E_PASSWORD` CI variable should be set to perform Auth0 login.


## Run tests locally
Expand Down
1 change: 1 addition & 0 deletions e2e/config/local.playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ReporterDescription } from '@playwright/test';
* Config used for a local run
*/
config.workers = 2;
config.retries = 0;
config.use!.headless = true;
config.use!.video = 'on';
config.use!.trace = 'on';
Expand Down
2 changes: 2 additions & 0 deletions e2e/config/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export default defineConfig({
],
outputDir: '../test-results',
timeout: 60000,
retries: 1,
maxFailures: 10,
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
browserName: 'chromium',
Expand Down
7 changes: 7 additions & 0 deletions e2e/src/core/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Auth0Page } from '@/e2e/src/ui/pages/auth0Page';

import { DialHomePage } from '../ui/pages';
import { LoginPage } from '../ui/pages';
import {
Expand Down Expand Up @@ -49,6 +51,7 @@ const test = base.extend<
ReportAttributes & {
dialHomePage: DialHomePage;
loginPage: LoginPage;
auth0Page: Auth0Page;
chatBar: ChatBar;
promptBar: PromptBar;
chat: Chat;
Expand Down Expand Up @@ -119,6 +122,10 @@ const test = base.extend<
const loginPage = new LoginPage(page);
await use(loginPage);
},
auth0Page: async ({ page }, use) => {
const auth0Page = new Auth0Page(page);
await use(auth0Page);
},
chatBar: async ({ dialHomePage }, use) => {
const chatBar = dialHomePage.getChatBar();
await use(chatBar);
Expand Down
3 changes: 3 additions & 0 deletions e2e/src/testData/expectedConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export enum MenuOptions {
export = 'Export',
moveTo = 'Move to',
share = 'Share',
publish = 'Publish',
update = 'Update',
unpublish = 'Unpublish',
delete = 'Delete',
newFolder = 'New folder',
}
Expand Down
2 changes: 2 additions & 0 deletions e2e/src/tests/chatBarConversation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ test('Menu for New conversation', async ({
MenuOptions.export,
MenuOptions.moveTo,
MenuOptions.share,
MenuOptions.publish,
MenuOptions.delete,
]);
});
Expand Down Expand Up @@ -321,6 +322,7 @@ test(
MenuOptions.export,
MenuOptions.moveTo,
MenuOptions.share,
MenuOptions.publish,
MenuOptions.delete,
]);
},
Expand Down
2 changes: 2 additions & 0 deletions e2e/src/tests/compareMode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,8 @@ test(
await dialHomePage.openHomePage();
await dialHomePage.waitForPageLoaded();
await compare.waitForComparedConversationsLoaded();
await dialHomePage.throttleAPIResponse(API.chatHost);

await chat.sendRequestInCompareMode('write down 30 adjectives', {
rightEntity: firstConversation.model.id,
leftEntity: secondConversation.model.id,
Expand Down
10 changes: 8 additions & 2 deletions e2e/src/tests/desktopAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ import test from '../core/fixtures';

import { API } from '@/e2e/src/testData';

test('Authenticate', async ({ page, loginPage, localStorageManager }) => {
test('Authenticate', async ({
page,
loginPage,
auth0Page,
localStorageManager,
}) => {
await loginPage.navigateToBaseUrl();
const retrievedResponses = await loginPage.loginToChatBot();
await loginPage.ssoSignInButton.click();
const retrievedResponses = await auth0Page.loginToChatBot();
process.env.MODELS = retrievedResponses.get(API.modelsHost);
process.env.ADDONS = retrievedResponses.get(API.addonsHost);
process.env.RECENT_ADDONS = await localStorageManager.getRecentAddons();
Expand Down
7 changes: 4 additions & 3 deletions e2e/src/tests/folderPrompts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,18 @@ test('Prompt is moved out of the folder via drag&drop', async ({
folderPrompts,
localStorageManager,
prompts,
promptBar,
setTestIds,
}) => {
setTestIds('EPMRTC-961');
const promptInFolder = promptData.prepareDefaultPromptInFolder();
await localStorageManager.setFolders(promptInFolder.folders);
await localStorageManager.setPrompts(promptInFolder.prompts[0]);
await localStorageManager.setOpenedFolders(promptInFolder.folders);

await dialHomePage.openHomePage();
await dialHomePage.waitForPageLoaded();
await folderPrompts.expandCollapseFolder(promptInFolder.folders.name);
await folderPrompts.dropPromptFromFolder(
await dialHomePage.waitForPageLoaded({ isNewConversationVisible: true });
await promptBar.dropPromptFromFolder(
promptInFolder.folders.name,
promptInFolder.prompts[0].name,
);
Expand Down
1 change: 1 addition & 0 deletions e2e/src/tests/prompts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ test('Prompt menu', async ({
MenuOptions.export,
MenuOptions.moveTo,
MenuOptions.share,
MenuOptions.publish,
MenuOptions.delete,
]);
});
Expand Down
8 changes: 6 additions & 2 deletions e2e/src/tests/workWithModels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { availableThemes } from '@/src/types/settings';

import test from '@/e2e/src/core/fixtures';
import {
API,
ExpectedConstants,
ExpectedMessages,
ModelIds,
Expand All @@ -15,7 +16,7 @@ import { expect } from '@playwright/test';

const userRequests = ['first request', 'second request', 'third request'];
const requestTerm = 'qwer';
const request = 'write down 30 adjectives';
const request = 'write cinderella story';
const expectedResponse = 'The sky is blue.';
const sysPrompt = `Type: "${expectedResponse}" if user types ${requestTerm}`;
let gpt35Model: OpenAIEntityModel;
Expand Down Expand Up @@ -370,6 +371,7 @@ test(
await test.step('Send request and stop generation immediately', async () => {
await dialHomePage.openHomePage();
await dialHomePage.waitForPageLoaded({ isNewConversationVisible: true });
await dialHomePage.throttleAPIResponse(API.chatHost);
await chat.sendRequestWithButton(request, false);
await chat.stopGenerating.click();
});
Expand Down Expand Up @@ -441,7 +443,8 @@ test(
});

await test.step('Send request and stop generation when partial content received', async () => {
await chat.regenerateResponse(false);
await dialHomePage.unRouteResponse(API.chatHost);
await chat.regenerateResponse(false);
await chatMessages.waitForPartialMessageReceived(2);
await chat.stopGenerating.click();
});
Expand Down Expand Up @@ -498,6 +501,7 @@ test(
await test.step('Send request, verify Compare button is disabled while generating the response and stop generation immediately', async () => {
await dialHomePage.openHomePage();
await dialHomePage.waitForPageLoaded({ isNewConversationVisible: true });
await dialHomePage.throttleAPIResponse(API.chatHost, 1500);
await chat.sendRequestWithButton(request, false);

const isCompareButtonEnabled =
Expand Down
30 changes: 30 additions & 0 deletions e2e/src/ui/pages/auth0Page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { BasePage } from './basePage';

import { Auth0 } from '@/e2e/src/ui/webElements/auth0';

export class Auth0Page extends BasePage {
private auth0!: Auth0;

getAuth0(): Auth0 {
if (!this.auth0) {
this.auth0 = new Auth0(this.page);
}
return this.auth0;
}

async loginToChatBot() {
await this.page.waitForLoadState('networkidle');
await this.page.waitForLoadState('domcontentloaded');
const auth0Form = this.getAuth0();
await auth0Form.setCredentials(
process.env.E2E_USERNAME!,
process.env.E2E_PASSWORD!,
);
return this.waitFoApiResponsesReceived(
() => auth0Form.loginButton.click(),
{
setEntitiesEnvVars: true,
},
);
}
}
14 changes: 14 additions & 0 deletions e2e/src/ui/pages/basePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface UploadDownloadData {
}

const apiTimeout = 35000;
const responseThrottlingTimeout = 2500;

export class BasePage {
protected page: Page;
Expand Down Expand Up @@ -74,6 +75,19 @@ export class BasePage {
return responseBodies;
}

async throttleAPIResponse(url: string, timeout?: number) {
await this.page.route(url, async (route) => {
await new Promise((f) =>
setTimeout(f, timeout ?? responseThrottlingTimeout),
);
await route.continue();
});
}

async unRouteResponse(url: string) {
await this.page.unroute(url);
}

async reloadPage() {
await this.page.reload();
await this.page.waitForLoadState('networkidle');
Expand Down
7 changes: 6 additions & 1 deletion e2e/src/ui/pages/loginPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ import { LoginSelectors } from '../selectors';
import { BaseElement } from '../webElements';
import { BasePage } from './basePage';

import { Tags } from '@/e2e/src/ui/domData';
import * as process from 'process';

export class LoginPage extends BasePage {
private tokenInput = new BaseElement(this.page, LoginSelectors.token);
public ssoSignInButton = new BaseElement(
this.page,
`${Tags.button}.${Tags.button}`,
);
private signInButton = new BaseElement(
this.page,
LoginSelectors.signIn,
).getElementLocatorByText(ExpectedConstants.signInButtonTitle);

async loginToChatBot() {
async loginToChatBotWithToken() {
const token = process.env.PREVIEW_TEST_TOKEN
? process.env.PREVIEW_TEST_TOKEN!.split(',')[0]
: process.env.AUTH_TEST_TOKEN!.split(',')[0];
Expand Down
4 changes: 4 additions & 0 deletions e2e/src/ui/selectors/loginSelectors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export const LoginSelectors = {
token: '#input-access_token-for-credentials-provider',
signIn: '[type=submit]',
auth0Container: '.auth0-lock-widget-container',
username: '[name="email"]',
password: '[name="password"]',
login: '[name="submit"]',
};
4 changes: 2 additions & 2 deletions e2e/src/ui/selectors/sideBarSelectors.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Attributes, Tags } from '@/e2e/src/ui/domData';

export const SideBarSelectors = {
chatBar: '[data-qa="sidebar"].fixed.left-0',
promptBar: '[data-qa="sidebar"].fixed.right-0',
chatBar: '[data-qa="chatbar"]',
promptBar: '[data-qa="promptbar"]',
folder: '[data-qa="folder"]',
folderName: '[data-qa="folder-name"]',
dotsMenu: '[aria-haspopup="menu"]',
Expand Down
22 changes: 22 additions & 0 deletions e2e/src/ui/webElements/auth0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { LoginSelectors } from '@/e2e/src/ui/selectors';
import { BaseElement } from '@/e2e/src/ui/webElements/baseElement';
import { Page } from '@playwright/test';

export class Auth0 extends BaseElement {
constructor(page: Page) {
super(page, LoginSelectors.auth0Container);
}

public usernameInput = this.getChildElementBySelector(
LoginSelectors.username,
);
public passwordInput = this.getChildElementBySelector(
LoginSelectors.password,
);
public loginButton = this.getChildElementBySelector(LoginSelectors.login);

public async setCredentials(username: string, password: string) {
await this.usernameInput.fillInInput(username);
await this.passwordInput.fillInInput(password);
}
}
Loading

0 comments on commit 7af7df5

Please sign in to comment.