UNPKG

chrome-devtools-frontend

Version:
477 lines (402 loc) • 15.2 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import { describeWithEnvironment, setupActionRegistry, } from '../../testing/EnvironmentHelpers.js'; import * as RenderCoordinator from '../../ui/components/render_coordinator/render_coordinator.js'; import * as Components from './components/components.js'; import * as Models from './models/models.js'; import {RecorderActions} from './recorder-actions/recorder-actions.js'; import {RecorderController} from './recorder.js'; describeWithEnvironment('RecorderController', () => { setupActionRegistry(); function makeRecording(): Models.RecordingStorage.StoredRecording { const step = { type: Models.Schema.StepType.Navigate as const, url: 'https://example.com', }; const recording = { storageName: 'test', flow: {title: 'test', steps: [step]}, }; return recording; } async function setupController( recording: Models.RecordingStorage.StoredRecording, ): Promise<RecorderController.RecorderController> { const controller = new RecorderController.RecorderController(); controller.setCurrentPageForTesting(RecorderController.Pages.RECORDING_PAGE); controller.setCurrentRecordingForTesting(recording); controller.connectedCallback(); await RenderCoordinator.done(); return controller; } describe('Navigation', () => { it('should return back to the previous page on recordingcancelled event', async () => { const previousPage = RecorderController.Pages.ALL_RECORDINGS_PAGE; const controller = new RecorderController.RecorderController(); controller.setCurrentPageForTesting(previousPage); controller.setCurrentPageForTesting( RecorderController.Pages.CREATE_RECORDING_PAGE, ); controller.connectedCallback(); await RenderCoordinator.done(); const createRecordingView = controller.shadowRoot?.querySelector( 'devtools-create-recording-view', ); assert.isOk(createRecordingView); createRecordingView?.dispatchEvent( new Components.CreateRecordingView.RecordingCancelledEvent(), ); assert.strictEqual(controller.getCurrentPageForTesting(), previousPage); }); }); describe('StepView', () => { async function dispatchRecordingViewEvent( controller: RecorderController.RecorderController, event: Event, ): Promise<void> { const recordingView = controller.shadowRoot?.querySelector( 'devtools-recording-view', ); assert.isOk(recordingView); recordingView?.dispatchEvent(event); await RenderCoordinator.done(); } beforeEach(() => { Models.RecordingStorage.RecordingStorage.instance().clearForTest(); }); after(() => { Models.RecordingStorage.RecordingStorage.instance().clearForTest(); }); it('should add a new step after a step', async () => { const recording = makeRecording(); const controller = await setupController(recording); await dispatchRecordingViewEvent( controller, new Components.StepView.AddStep( recording.flow.steps[0], Components.StepView.AddStepPosition.AFTER, ), ); const flow = controller.getUserFlow(); assert.deepEqual(flow, { title: 'test', steps: [ { type: Models.Schema.StepType.Navigate as const, url: 'https://example.com', }, { type: Models.Schema.StepType.WaitForElement as const, selectors: ['body'], }, ], }); }); it('should add a new step after a section', async () => { const recording = makeRecording(); const controller = await setupController(recording); const sections = controller.getSectionsForTesting(); if (!sections) { throw new Error('Controller is missing sections'); } assert.lengthOf(sections, 1); await dispatchRecordingViewEvent( controller, new Components.StepView.AddStep( sections[0], Components.StepView.AddStepPosition.AFTER, ), ); const flow = controller.getUserFlow(); assert.deepEqual(flow, { title: 'test', steps: [ { type: Models.Schema.StepType.Navigate as const, url: 'https://example.com', }, { type: Models.Schema.StepType.WaitForElement as const, selectors: ['body'], }, ], }); }); it('should add a new step before a step', async () => { const recording = makeRecording(); const controller = await setupController(recording); await dispatchRecordingViewEvent( controller, new Components.StepView.AddStep( recording.flow.steps[0], Components.StepView.AddStepPosition.BEFORE, ), ); const flow = controller.getUserFlow(); assert.deepEqual(flow, { title: 'test', steps: [ { type: Models.Schema.StepType.WaitForElement as const, selectors: ['body'], }, { type: Models.Schema.StepType.Navigate as const, url: 'https://example.com', }, ], }); }); it('should delete a step', async () => { const recording = makeRecording(); const controller = await setupController(recording); await dispatchRecordingViewEvent( controller, new Components.StepView.RemoveStep(recording.flow.steps[0]), ); const flow = controller.getUserFlow(); assert.deepEqual(flow, {title: 'test', steps: []}); }); it('should adding a new step before a step with a breakpoint update the breakpoint indexes correctly', async () => { const recording = makeRecording(); const controller = await setupController(recording); const stepIndex = 3; await dispatchRecordingViewEvent( controller, new Components.StepView.AddBreakpointEvent(stepIndex), ); assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), [ stepIndex, ]); await dispatchRecordingViewEvent( controller, new Components.StepView.AddStep( recording.flow.steps[0], Components.StepView.AddStepPosition.BEFORE, ), ); // Breakpoint index moves to the next index assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), [ stepIndex + 1, ]); }); it('should removing a step before a step with a breakpoint update the breakpoint indexes correctly', async () => { const recording = makeRecording(); const controller = await setupController(recording); const stepIndex = 3; await dispatchRecordingViewEvent( controller, new Components.StepView.AddBreakpointEvent(stepIndex), ); assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), [ stepIndex, ]); await dispatchRecordingViewEvent( controller, new Components.StepView.RemoveStep(recording.flow.steps[0]), ); // Breakpoint index moves to the previous index assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), [ stepIndex - 1, ]); }); it('should removing a step with a breakpoint remove the breakpoint index as well', async () => { const recording = makeRecording(); const controller = await setupController(recording); const stepIndex = 0; await dispatchRecordingViewEvent( controller, new Components.StepView.AddBreakpointEvent(stepIndex), ); assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), [ stepIndex, ]); await dispatchRecordingViewEvent( controller, new Components.StepView.RemoveStep(recording.flow.steps[stepIndex]), ); // Breakpoint index is removed assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), []); }); it('should "add breakpoint" event add a breakpoint', async () => { const recording = makeRecording(); const controller = await setupController(recording); const stepIndex = 1; assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), []); await dispatchRecordingViewEvent( controller, new Components.StepView.AddBreakpointEvent(stepIndex), ); assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), [ stepIndex, ]); }); it('should "remove breakpoint" event remove a breakpoint', async () => { const recording = makeRecording(); const controller = await setupController(recording); const stepIndex = 1; await dispatchRecordingViewEvent( controller, new Components.StepView.AddBreakpointEvent(stepIndex), ); assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), [ stepIndex, ]); await dispatchRecordingViewEvent( controller, new Components.StepView.RemoveBreakpointEvent(stepIndex), ); assert.deepEqual(controller.getStepBreakpointIndexesForTesting(), []); }); }); describe('Create new recording action', () => { it('should execute action', async () => { const recording = makeRecording(); const controller = await setupController(recording); await controller.handleActions(RecorderActions.CREATE_RECORDING); assert.strictEqual( controller.getCurrentPageForTesting(), RecorderController.Pages.CREATE_RECORDING_PAGE, ); }); it('should not execute action while recording', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setIsRecordingStateForTesting(true); await controller.handleActions(RecorderActions.CREATE_RECORDING); assert.strictEqual( controller.getCurrentPageForTesting(), RecorderController.Pages.RECORDING_PAGE, ); }); it('should not execute action while replaying', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setRecordingStateForTesting({ isPlaying: true, isPausedOnBreakpoint: false, }); await controller.handleActions(RecorderActions.CREATE_RECORDING); assert.strictEqual( controller.getCurrentPageForTesting(), RecorderController.Pages.RECORDING_PAGE, ); }); }); describe('Action is possible', () => { it('should return true for create action when not replaying or recording', async () => { const recording = makeRecording(); const controller = await setupController(recording); assert.isTrue( controller.isActionPossible(RecorderActions.CREATE_RECORDING), ); }); it('should return false for create action when recording', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setRecordingStateForTesting({ isPlaying: true, isPausedOnBreakpoint: false, }); assert.isFalse( controller.isActionPossible(RecorderActions.CREATE_RECORDING), ); }); it('should return false for create action when replaying', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setIsRecordingStateForTesting(true); assert.isFalse( controller.isActionPossible(RecorderActions.CREATE_RECORDING), ); }); it('should return correct value for start/stop action', async () => { const recording = makeRecording(); const controller = await setupController(recording); assert.isTrue( controller.isActionPossible(RecorderActions.START_RECORDING), ); controller.setRecordingStateForTesting({ isPlaying: true, isPausedOnBreakpoint: false, }); assert.isFalse( controller.isActionPossible(RecorderActions.START_RECORDING), ); }); it('should return true for replay action when on the recording page', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setCurrentPageForTesting( RecorderController.Pages.RECORDING_PAGE, ); assert.isTrue( controller.isActionPossible(RecorderActions.REPLAY_RECORDING), ); }); it('should return false for replay action when not on the recording page', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setCurrentPageForTesting( RecorderController.Pages.ALL_RECORDINGS_PAGE, ); assert.isFalse( controller.isActionPossible(RecorderActions.REPLAY_RECORDING), ); controller.setCurrentPageForTesting( RecorderController.Pages.CREATE_RECORDING_PAGE, ); assert.isFalse( controller.isActionPossible(RecorderActions.REPLAY_RECORDING), ); controller.setCurrentPageForTesting(RecorderController.Pages.START_PAGE); assert.isFalse( controller.isActionPossible(RecorderActions.REPLAY_RECORDING), ); controller.setRecordingStateForTesting({ isPlaying: true, isPausedOnBreakpoint: false, }); controller.setCurrentPageForTesting( RecorderController.Pages.RECORDING_PAGE, ); assert.isFalse( controller.isActionPossible(RecorderActions.REPLAY_RECORDING), ); }); it('should true for toggle when on the recording page', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setCurrentPageForTesting( RecorderController.Pages.RECORDING_PAGE, ); assert.isTrue( controller.isActionPossible(RecorderActions.TOGGLE_CODE_VIEW), ); }); it('should false for toggle when on the recording page', async () => { const recording = makeRecording(); const controller = await setupController(recording); controller.setCurrentPageForTesting( RecorderController.Pages.ALL_RECORDINGS_PAGE, ); assert.isFalse( controller.isActionPossible(RecorderActions.TOGGLE_CODE_VIEW), ); controller.setCurrentPageForTesting(RecorderController.Pages.START_PAGE); assert.isFalse( controller.isActionPossible(RecorderActions.TOGGLE_CODE_VIEW), ); controller.setCurrentPageForTesting( RecorderController.Pages.ALL_RECORDINGS_PAGE, ); assert.isFalse( controller.isActionPossible(RecorderActions.TOGGLE_CODE_VIEW), ); }); }); });