feat: add Accounts page with QR code display for WhatsApp re-authentication
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { AccountCard } from './AccountCard';
|
||||
|
||||
const activeAccount = {
|
||||
id: 'acc_1',
|
||||
jid: '111@s.whatsapp.net',
|
||||
displayName: 'My Account',
|
||||
status: 'ACTIVE',
|
||||
platform: 'whatsapp',
|
||||
};
|
||||
|
||||
const disconnectedAccount = {
|
||||
id: 'acc_2',
|
||||
jid: '222@s.whatsapp.net',
|
||||
displayName: null,
|
||||
status: 'DISCONNECTED',
|
||||
platform: 'whatsapp',
|
||||
};
|
||||
|
||||
let fetchSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
fetchSpy = jest.spyOn(global, 'fetch');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('AccountCard', () => {
|
||||
it('shows displayName and Connected badge when ACTIVE', () => {
|
||||
render(<AccountCard account={activeAccount} />);
|
||||
expect(screen.getByText('My Account')).toBeInTheDocument();
|
||||
expect(screen.getByText('Connected')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('falls back to jid when displayName is null', () => {
|
||||
render(<AccountCard account={disconnectedAccount} />);
|
||||
expect(screen.getByText('222@s.whatsapp.net')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows Awaiting scan badge when DISCONNECTED', () => {
|
||||
fetchSpy.mockResolvedValue(
|
||||
new Response(JSON.stringify({ status: 'DISCONNECTED', qrDataUrl: null }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
render(<AccountCard account={disconnectedAccount} />);
|
||||
expect(screen.getByText('Awaiting scan')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not fetch QR when account is ACTIVE', () => {
|
||||
render(<AccountCard account={activeAccount} />);
|
||||
expect(fetchSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fetches QR from /api/accounts/:id/qr when DISCONNECTED', async () => {
|
||||
fetchSpy.mockResolvedValue(
|
||||
new Response(JSON.stringify({ status: 'DISCONNECTED', qrDataUrl: null }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
render(<AccountCard account={disconnectedAccount} />);
|
||||
await waitFor(() =>
|
||||
expect(fetchSpy).toHaveBeenCalledWith('/api/accounts/acc_2/qr'),
|
||||
);
|
||||
});
|
||||
|
||||
it('shows QR image when qrDataUrl is returned', async () => {
|
||||
fetchSpy.mockResolvedValue(
|
||||
new Response(
|
||||
JSON.stringify({ status: 'DISCONNECTED', qrDataUrl: 'data:image/png;base64,abc123' }),
|
||||
{ status: 200, headers: { 'Content-Type': 'application/json' } },
|
||||
),
|
||||
);
|
||||
render(<AccountCard account={disconnectedAccount} />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('img', { name: /qr code/i })).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByRole('img', { name: /qr code/i })).toHaveAttribute(
|
||||
'src',
|
||||
'data:image/png;base64,abc123',
|
||||
);
|
||||
});
|
||||
|
||||
it('shows waiting message when DISCONNECTED but no QR yet', async () => {
|
||||
fetchSpy.mockResolvedValue(
|
||||
new Response(JSON.stringify({ status: 'DISCONNECTED', qrDataUrl: null }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
render(<AccountCard account={disconnectedAccount} />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/waiting for qr/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user