updates on the design and the onboarding things

This commit is contained in:
2026-09-30 14:45:49 +05:30
parent 53199127ba
commit ede1731fa5
11 changed files with 907 additions and 336 deletions

View File

@@ -191,7 +191,7 @@ describe('Agent Studio page', () => {
// The engine reads it only once its Phase 5 build is deployed; say so, not "live".
expect(note).toHaveTextContent(/once its registry-reading build is deployed/);
expect(note).toHaveTextContent(/environment defaults/);
expect(note).toHaveTextContent(/The Test tab runs real Claude calls/);
expect(note).toHaveTextContent(/The Test tab runs real AI model calls/);
expect(note).not.toHaveTextContent(/The Test tab is a simulation/);
// Since Phase 3 the console skills DO run on these settings; the note must not say otherwise.
expect(note).toHaveTextContent(/run on these settings now/);

View File

@@ -23,6 +23,13 @@ jest.mock('@/api/doormile', () => ({
onboardClient: jest.fn(),
getOnboardedClients: jest.fn(),
getOnboardingCities: jest.fn(),
updateOnboardedClient: jest.fn(),
deleteOnboardedClient: jest.fn(),
}));
jest.mock('@/api/doormile/notify', () => ({
OpenToast: jest.fn(),
messageOf: (err, fallback = 'Something went wrong') => err?.response?.data?.message || err?.message || fallback,
}));
let mockAuth = { user: { email: 'admin@doormile.com', role: 'admin', tenantid: null }, isClient: false };
@@ -67,8 +74,79 @@ beforeEach(() => {
jest.clearAllMocks();
api.getOnboardingCities.mockResolvedValue(CITIES);
api.getOnboardedClients.mockResolvedValue([
{ tenantid: 12, tenantname: 'Older Client', primaryemail: 'a@old.example', primarycontact: '9000000000', status: 'Active', loginemail: 'a@old.example', loginrole: 'manager', logincreatedat: '2026-09-28T10:00:00Z' },
{ authid: 31, tenantid: 12, tenantname: 'Older Client', primaryemail: 'a@old.example', primarycontact: '9000000000', status: 'Active', requiredeliveryotp: false, contactname: 'Old Contact', loginemail: 'a@old.example', loginrole: 'manager', logincreatedat: '2026-09-28T10:00:00Z' },
]);
api.updateOnboardedClient.mockResolvedValue({ success: true, data: {} });
api.deleteOnboardedClient.mockResolvedValue({ success: true, data: {} });
});
describe('Edit and Delete on a client login', () => {
it('shows Edit and Delete on each row', async () => {
renderPage();
expect(await screen.findByRole('button', { name: 'Edit Older Client' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Delete Older Client' })).toBeInTheDocument();
});
it('sends only the fields that changed', async () => {
renderPage();
fireEvent.click(await screen.findByRole('button', { name: 'Edit Older Client' }));
const dialog = await screen.findByRole('dialog');
const save = screen.getByRole('button', { name: /Save changes/ });
expect(save).toBeDisabled(); // nothing changed yet
fireEvent.change(dialog.querySelector('select'), { target: { value: 'Inactive' } });
fireEvent.change(screen.getAllByLabelText(/Mobile number/)[1], { target: { value: '9123456780' } });
fireEvent.click(save);
await waitFor(() => expect(api.updateOnboardedClient).toHaveBeenCalledWith(31, { phone: '9123456780', status: 'Inactive' }));
});
it('resets the password only when one is entered, and checks its length', async () => {
renderPage();
fireEvent.click(await screen.findByRole('button', { name: 'Edit Older Client' }));
await screen.findByRole('dialog');
fireEvent.change(document.getElementById('edit-client-password'), { target: { value: 'short' } });
fireEvent.click(screen.getByRole('button', { name: /Save changes/ }));
await waitFor(() => expect(document.getElementById('edit-client-password-error')).toHaveTextContent('At least 8 characters'));
expect(api.updateOnboardedClient).not.toHaveBeenCalled();
fireEvent.change(document.getElementById('edit-client-password'), { target: { value: 'new-pass-123' } });
fireEvent.click(screen.getByRole('button', { name: /Save changes/ }));
await waitFor(() => expect(api.updateOnboardedClient).toHaveBeenCalledWith(31, { password: 'new-pass-123' }));
});
it('shows a server conflict in the dialog', async () => {
api.updateOnboardedClient.mockRejectedValue({ response: { status: 409, data: { message: 'this email already has a console login' } } });
renderPage();
fireEvent.click(await screen.findByRole('button', { name: 'Edit Older Client' }));
await screen.findByRole('dialog');
fireEvent.change(screen.getAllByLabelText(/Login email/)[1], { target: { value: 'taken@x.example' } });
fireEvent.click(screen.getByRole('button', { name: /Save changes/ }));
expect(await screen.findByText('this email already has a console login')).toBeInTheDocument();
});
it('never calls /clients/undefined when the backend is too old to send ids', async () => {
api.getOnboardedClients.mockResolvedValue([
{ tenantid: 12, tenantname: 'Older Client', primarycontact: '9000000000', status: 'Active', loginemail: 'a@old.example', loginrole: 'manager' },
]);
renderPage();
const edit = await screen.findByRole('button', { name: 'Edit Older Client' });
expect(edit).toBeDisabled();
expect(screen.getByRole('button', { name: 'Delete Older Client' })).toBeDisabled();
expect(screen.getByText('Edit and Delete are not available on this server yet')).toBeInTheDocument();
fireEvent.click(edit);
expect(api.updateOnboardedClient).not.toHaveBeenCalled();
expect(api.deleteOnboardedClient).not.toHaveBeenCalled();
});
it('deletes only after the company name is typed', async () => {
renderPage();
fireEvent.click(await screen.findByRole('button', { name: 'Delete Older Client' }));
await screen.findByRole('dialog');
const remove = screen.getByRole('button', { name: /Remove login/ });
expect(remove).toBeDisabled();
fireEvent.change(screen.getByLabelText(/to confirm/), { target: { value: 'older client' } });
expect(remove).not.toBeDisabled();
fireEvent.click(remove);
await waitFor(() => expect(api.deleteOnboardedClient).toHaveBeenCalledWith(31));
});
});
describe('Client onboarding page', () => {