blob: 0eb1fff09a02941fbb4e433f72a157f4676d3820 [file]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Router } from '@angular/router';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { MessageReceiveDataTypeMap, WebSocketMessage } from '@zeppelin/sdk';
import { TicketService } from '@zeppelin/services';
import authInfoCapture from '../../e2e/fixtures/notebook-auth/ws-global-auth-info.json?raw';
import errorInfoCapture from '../../e2e/fixtures/notebook-auth/ws-global-error-info.json?raw';
import sessionLogoutCapture from '../../e2e/fixtures/notebook-auth/ws-session-logout.json?raw';
import { AppMessageInterceptor } from './app-message.interceptor';
type Message = WebSocketMessage<MessageReceiveDataTypeMap>;
/** The first frame of `op` the server sent in a captured fixture. */
const capturedFrame = (raw: string, op: string): Message => {
const { records } = JSON.parse(raw) as {
records: Array<{ kind: string; websocket?: { direction: string; payloadText: string } }>;
};
const frame = records
.filter(record => record.kind === 'websocket' && record.websocket!.direction === 'receive')
.map(record => JSON.parse(record.websocket!.payloadText) as Message)
.find(message => message.op === op);
if (!frame) throw new Error(`No captured ${op}`);
return frame;
};
describe('AppMessageInterceptor with captured shell messages', () => {
let navigate: ReturnType<typeof vi.fn>;
let warning: ReturnType<typeof vi.fn>;
let create: ReturnType<typeof vi.fn>;
let confirm: ReturnType<typeof vi.fn>;
let ticketService: TicketService;
const interceptor = () =>
new AppMessageInterceptor(
{ navigate } as unknown as Router,
{ warning } as unknown as NzNotificationService,
ticketService,
{ create, confirm } as unknown as NzModalService
);
beforeEach(() => {
navigate = vi.fn(() => Promise.resolve(true));
warning = vi.fn();
create = vi.fn();
confirm = vi.fn();
ticketService = { ticket: { principal: 'signed-in', ticket: 'kept', roles: '["role3"]' } } as TicketService;
});
it('presents a captured AUTH_INFO without changing the authentication state', () => {
const before = structuredClone(ticketService.ticket);
const message = capturedFrame(authInfoCapture, 'AUTH_INFO');
expect(interceptor().received(message)).toBe(message);
expect(create).toHaveBeenCalledOnce();
expect(create.mock.calls[0][0]).toMatchObject({ nzTitle: 'Insufficient privileges' });
expect(confirm).not.toHaveBeenCalled();
expect(ticketService.ticket).toEqual(before);
expect(navigate).not.toHaveBeenCalled();
});
it('presents a captured AUTH_INFO to an anonymous ticket as a plain confirmation', () => {
ticketService.ticket.roles = '[]';
interceptor().received(capturedFrame(authInfoCapture, 'AUTH_INFO'));
expect(confirm).toHaveBeenCalledOnce();
expect(create).not.toHaveBeenCalled();
});
it('shows a captured global ERROR_INFO as a host notification', () => {
const message = capturedFrame(errorInfoCapture, 'ERROR_INFO');
interceptor().received(message);
expect(warning).toHaveBeenCalledExactlyOnceWith(
'ERROR',
(message.data as { info: string }).info,
expect.anything()
);
expect(create).not.toHaveBeenCalled();
});
it('leaves a captured SESSION_LOGOUT unhandled while the same interceptor handles AUTH_INFO', () => {
const before = structuredClone(ticketService.ticket);
const host = interceptor();
const logout = capturedFrame(sessionLogoutCapture, 'SESSION_LOGOUT');
expect(host.received(logout)).toBe(logout);
expect([create, confirm, warning, navigate].map(spy => spy.mock.calls.length)).toEqual([0, 0, 0, 0]);
expect(ticketService.ticket).toEqual(before);
host.received(capturedFrame(authInfoCapture, 'AUTH_INFO'));
expect(create).toHaveBeenCalledOnce();
});
});