Merge pull request #2693 from janhq/auto/invalid-chat
feat: Select GPT model from Hub and Chat with Invalid API Key
This commit is contained in:
commit
32fd360302
@ -111,7 +111,7 @@ jobs:
|
|||||||
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
||||||
|
|
||||||
test-on-windows:
|
test-on-windows:
|
||||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
if: github.event_name == 'push'
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { test, appInfo } from '../config/fixtures'
|
import { test, appInfo, page, TIMEOUT } from '../config/fixtures'
|
||||||
import { expect } from '@playwright/test'
|
import { expect } from '@playwright/test'
|
||||||
|
|
||||||
test.beforeAll(async () => {
|
test.beforeAll(async () => {
|
||||||
@ -16,4 +16,9 @@ test.beforeAll(async () => {
|
|||||||
test('explores hub', async ({ hubPage }) => {
|
test('explores hub', async ({ hubPage }) => {
|
||||||
await hubPage.navigateByMenu()
|
await hubPage.navigateByMenu()
|
||||||
await hubPage.verifyContainerVisible()
|
await hubPage.verifyContainerVisible()
|
||||||
|
const useModelBtn= page.getByTestId(/^use-model-btn-.*/).first()
|
||||||
|
|
||||||
|
await expect(useModelBtn).toBeVisible({
|
||||||
|
timeout: TIMEOUT,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
35
electron/tests/e2e/thread.e2e.spec.ts
Normal file
35
electron/tests/e2e/thread.e2e.spec.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { expect } from '@playwright/test'
|
||||||
|
import { page, test, TIMEOUT } from '../config/fixtures'
|
||||||
|
|
||||||
|
test('Select GPT model from Hub and Chat with Invalid API Key', async ({ hubPage }) => {
|
||||||
|
await hubPage.navigateByMenu()
|
||||||
|
await hubPage.verifyContainerVisible()
|
||||||
|
|
||||||
|
// Select the first GPT model
|
||||||
|
await page
|
||||||
|
.locator('[data-testid^="use-model-btn"][data-testid*="gpt"]')
|
||||||
|
.first().click()
|
||||||
|
|
||||||
|
// Attempt to create thread and chat in Thread page
|
||||||
|
await page
|
||||||
|
.getByTestId('btn-create-thread')
|
||||||
|
.click()
|
||||||
|
|
||||||
|
await page
|
||||||
|
.getByTestId('txt-input-chat')
|
||||||
|
.fill('dummy value')
|
||||||
|
|
||||||
|
await page
|
||||||
|
.getByTestId('btn-send-chat')
|
||||||
|
.click()
|
||||||
|
|
||||||
|
await page.waitForFunction(() => {
|
||||||
|
const loaders = document.querySelectorAll('[data-testid$="loader"]');
|
||||||
|
return !loaders.length;
|
||||||
|
}, { timeout: TIMEOUT });
|
||||||
|
|
||||||
|
const APIKeyError = page.getByTestId('invalid-API-key-error')
|
||||||
|
await expect(APIKeyError).toBeVisible({
|
||||||
|
timeout: TIMEOUT,
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -8,8 +8,9 @@ export class BasePage {
|
|||||||
constructor(
|
constructor(
|
||||||
protected readonly page: Page,
|
protected readonly page: Page,
|
||||||
readonly action: CommonActions,
|
readonly action: CommonActions,
|
||||||
protected containerId: string
|
protected containerId: string,
|
||||||
) {}
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public getValue(key: string) {
|
public getValue(key: string) {
|
||||||
return this.action.getValue(key)
|
return this.action.getValue(key)
|
||||||
@ -24,7 +25,11 @@ export class BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async navigateByMenu() {
|
async navigateByMenu() {
|
||||||
await this.page.getByTestId(this.menuId).first().click()
|
await this.clickFirstElement(this.menuId)
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickFirstElement(testId: string) {
|
||||||
|
await this.page.getByTestId(testId).first().click()
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyContainerVisible() {
|
async verifyContainerVisible() {
|
||||||
@ -36,7 +41,7 @@ export class BasePage {
|
|||||||
await this.isElementVisible('img[alt="Jan - Logo"]')
|
await this.isElementVisible('img[alt="Jan - Logo"]')
|
||||||
}
|
}
|
||||||
|
|
||||||
//wait and find a specific element with it's selector and return Visible
|
//wait and find a specific element with its selector and return Visible
|
||||||
async isElementVisible(selector: any) {
|
async isElementVisible(selector: any) {
|
||||||
let isVisible = true
|
let isVisible = true
|
||||||
await this.page
|
await this.page
|
||||||
|
|||||||
@ -31,6 +31,7 @@ export default function GenerateResponse() {
|
|||||||
<div
|
<div
|
||||||
className="absolute left-0 top-0 h-full bg-gray-200"
|
className="absolute left-0 top-0 h-full bg-gray-200"
|
||||||
style={{ width: `${loader}%` }}
|
style={{ width: `${loader}%` }}
|
||||||
|
data-testid="response-loader"
|
||||||
/>
|
/>
|
||||||
<span className="relative z-10">Generating response...</span>
|
<span className="relative z-10">Generating response...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -40,6 +40,7 @@ export default function ModelStart() {
|
|||||||
<div
|
<div
|
||||||
className="absolute left-0 top-0 h-full bg-blue-200"
|
className="absolute left-0 top-0 h-full bg-blue-200"
|
||||||
style={{ width: `${loader}%` }}
|
style={{ width: `${loader}%` }}
|
||||||
|
data-testid="model-loader"
|
||||||
/>
|
/>
|
||||||
<span className="relative z-10">
|
<span className="relative z-10">
|
||||||
{stateModel.state === 'start' ? 'Starting' : 'Stopping'}
|
{stateModel.state === 'start' ? 'Starting' : 'Stopping'}
|
||||||
|
|||||||
@ -148,6 +148,7 @@ const ChatInput: React.FC = () => {
|
|||||||
'max-h-[400px] resize-none pr-20',
|
'max-h-[400px] resize-none pr-20',
|
||||||
fileUpload.length && 'rounded-t-none'
|
fileUpload.length && 'rounded-t-none'
|
||||||
)}
|
)}
|
||||||
|
data-testid="txt-input-chat"
|
||||||
style={{ height: '40px' }}
|
style={{ height: '40px' }}
|
||||||
ref={textareaRef}
|
ref={textareaRef}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
@ -320,6 +321,7 @@ const ChatInput: React.FC = () => {
|
|||||||
}
|
}
|
||||||
themes="primary"
|
themes="primary"
|
||||||
className="min-w-[100px]"
|
className="min-w-[100px]"
|
||||||
|
data-testid="btn-send-chat"
|
||||||
onClick={() => sendChatMessage(currentPrompt)}
|
onClick={() => sendChatMessage(currentPrompt)}
|
||||||
>
|
>
|
||||||
Send
|
Send
|
||||||
|
|||||||
@ -43,7 +43,7 @@ const ErrorMessage = ({ message }: { message: ThreadMessage }) => {
|
|||||||
case ErrorCode.InvalidApiKey:
|
case ErrorCode.InvalidApiKey:
|
||||||
case ErrorCode.InvalidRequestError:
|
case ErrorCode.InvalidRequestError:
|
||||||
return (
|
return (
|
||||||
<span>
|
<span data-testid="invalid-API-key-error">
|
||||||
Invalid API key. Please check your API key from{' '}
|
Invalid API key. Please check your API key from{' '}
|
||||||
<button
|
<button
|
||||||
className="font-medium text-primary dark:text-blue-400"
|
className="font-medium text-primary dark:text-blue-400"
|
||||||
|
|||||||
@ -121,6 +121,7 @@ const ExploreModelItemHeader: React.FC<Props> = ({ model, onClick, open }) => {
|
|||||||
className="min-w-[98px]"
|
className="min-w-[98px]"
|
||||||
onClick={onUseModelClick}
|
onClick={onUseModelClick}
|
||||||
disabled={serverEnabled}
|
disabled={serverEnabled}
|
||||||
|
data-testid={`use-model-btn-${model.id}`}
|
||||||
>
|
>
|
||||||
Use
|
Use
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user