/**
* Tests for OrcaCloudView — the RFC 8628 device-pairing flow: disconnected
* (Connect button), pairing (code + approval link + waiting), a completed
* poll flipping to connected, a denied poll surfacing an error, and disconnect.
*/
import { describe, it, expect } from 'vitest';
import { screen, waitFor, fireEvent } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { server } from '../mocks/server';
import { render } from '../utils';
import { OrcaCloudView } from '../../components/OrcaCloudView';
const DEVICE_START = {
user_code: 'ABCD-EF12',
verification_uri: 'https://cloud.orcaslicer.com/app/settings',
verification_uri_complete: 'https://cloud.orcaslicer.com/app/settings?user_code=ABCD-EF12',
interval: 5,
expires_in: 600,
};
const NO_PROFILES = { filament: [], printer: [], process: [] };
const disconnectedStatus = () =>
http.get('/api/v1/orca-cloud/status', () =>
HttpResponse.json({ connected: false, email: null, user_id: null }),
);
describe('OrcaCloudView', () => {
it('shows the Connect button when not connected', async () => {
server.use(disconnectedStatus());
render();
await waitFor(() => {
expect(screen.getByRole('button', { name: /Connect Orca Cloud/i })).toBeInTheDocument();
});
});
it('shows the pairing code and approval link after clicking Connect', async () => {
server.use(
disconnectedStatus(),
http.post('/api/v1/orca-cloud/device/start', () => HttpResponse.json(DEVICE_START)),
http.post('/api/v1/orca-cloud/device/poll', () =>
HttpResponse.json({ status: 'authorization_pending', connected: false, email: null, user_id: null }),
),
);
render();
await waitFor(() => {
expect(screen.getByRole('button', { name: /Connect Orca Cloud/i })).toBeInTheDocument();
});
fireEvent.click(screen.getByRole('button', { name: /Connect Orca Cloud/i }));
await waitFor(() => {
expect(screen.getByText('ABCD-EF12')).toBeInTheDocument();
});
expect(screen.getByText(/Waiting for you to approve/i)).toBeInTheDocument();
// The approval link points at the verification_uri_complete.
expect(screen.getByRole('link', { name: /Open Orca Cloud approval page/i })).toHaveAttribute(
'href',
DEVICE_START.verification_uri_complete,
);
});
it('flips to connected once a poll returns complete', async () => {
let connected = false;
server.use(
http.get('/api/v1/orca-cloud/status', () =>
HttpResponse.json(
connected
? { connected: true, email: null, user_id: 'user-123' }
: { connected: false, email: null, user_id: null },
),
),
http.post('/api/v1/orca-cloud/device/start', () => HttpResponse.json(DEVICE_START)),
http.post('/api/v1/orca-cloud/device/poll', () => {
connected = true;
return HttpResponse.json({ status: 'complete', connected: true, email: null, user_id: 'user-123' });
}),
http.get('/api/v1/orca-cloud/profiles', () => HttpResponse.json(NO_PROFILES)),
);
render();
await waitFor(() => {
expect(screen.getByRole('button', { name: /Connect Orca Cloud/i })).toBeInTheDocument();
});
fireEvent.click(screen.getByRole('button', { name: /Connect Orca Cloud/i }));
// The immediate first poll returns complete → status invalidates and the
// connected view (with the Disconnect control) appears. We key off the
// Disconnect button rather than the banner text, since the success toast
// also renders "Connected to Orca Cloud".
await waitFor(() => {
expect(screen.getByRole('button', { name: /Disconnect/i })).toBeInTheDocument();
});
});
it('surfaces an error and returns to Connect when the pairing is denied', async () => {
server.use(
disconnectedStatus(),
http.post('/api/v1/orca-cloud/device/start', () => HttpResponse.json(DEVICE_START)),
http.post('/api/v1/orca-cloud/device/poll', () =>
HttpResponse.json({ status: 'access_denied', connected: false, email: null, user_id: null }),
),
);
render();
await waitFor(() => {
expect(screen.getByRole('button', { name: /Connect Orca Cloud/i })).toBeInTheDocument();
});
fireEvent.click(screen.getByRole('button', { name: /Connect Orca Cloud/i }));
await waitFor(() => {
expect(screen.getByText(/denied/i)).toBeInTheDocument();
});
// Back on the Connect card, not stuck on the waiting screen.
expect(screen.getByRole('button', { name: /Connect Orca Cloud/i })).toBeInTheDocument();
expect(screen.queryByText(/Waiting for you to approve/i)).not.toBeInTheDocument();
});
it('clears the connection on Disconnect', async () => {
let connected = true;
server.use(
http.get('/api/v1/orca-cloud/status', () =>
HttpResponse.json(
connected
? { connected: true, email: null, user_id: 'user-123' }
: { connected: false, email: null, user_id: null },
),
),
http.get('/api/v1/orca-cloud/profiles', () => HttpResponse.json(NO_PROFILES)),
http.post('/api/v1/orca-cloud/logout', () => {
connected = false;
return HttpResponse.json({ success: true });
}),
);
render();
await waitFor(() => {
expect(screen.getByRole('button', { name: /Disconnect/i })).toBeInTheDocument();
});
fireEvent.click(screen.getByRole('button', { name: /Disconnect/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /Connect Orca Cloud/i })).toBeInTheDocument();
});
});
});