Skip to content

Commit

Permalink
Development: Speed up client tests for the online code editor (ls1int…
Browse files Browse the repository at this point in the history
  • Loading branch information
MDK5 authored Nov 5, 2021
1 parent 1d699d6 commit e56f95f
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 360 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import { CodeEditorAceComponent } from 'app/exercises/programming/shared/code-ed
import { MockCodeEditorRepositoryFileService } from '../../helpers/mocks/service/mock-code-editor-repository-file.service';
import { LocalStorageService } from 'ngx-webstorage';
import { MockLocalStorageService } from '../../helpers/mocks/service/mock-local-storage.service';
import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
import { MockComponent, MockPipe } from 'ng-mocks';
import { MockComponent } from 'ng-mocks';
import { CodeEditorTutorAssessmentInlineFeedbackComponent } from 'app/exercises/programming/assess/code-editor-tutor-assessment-inline-feedback.component';
import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service';

describe('CodeEditorAceComponent', () => {
let comp: CodeEditorAceComponent;
Expand All @@ -24,9 +24,9 @@ describe('CodeEditorAceComponent', () => {
let loadRepositoryFileStub: jest.SpyInstance;

beforeEach(() => {
return TestBed.configureTestingModule({
TestBed.configureTestingModule({
imports: [ArtemisTestModule, AceEditorModule],
declarations: [CodeEditorAceComponent, MockPipe(ArtemisTranslatePipe), MockComponent(CodeEditorTutorAssessmentInlineFeedbackComponent)],
declarations: [CodeEditorAceComponent, TranslatePipeMock, MockComponent(CodeEditorTutorAssessmentInlineFeedbackComponent)],
providers: [
CodeEditorFileService,
{ provide: CodeEditorRepositoryFileService, useClass: MockCodeEditorRepositoryFileService },
Expand All @@ -50,36 +50,36 @@ describe('CodeEditorAceComponent', () => {
it('without any inputs, should still render correctly without ace, showing a placeholder', () => {
fixture.detectChanges();
const placeholder = debugElement.query(By.css('#no-file-selected'));
expect(placeholder).toBeDefined();
expect(placeholder).not.toBe(null);
const aceEditor = debugElement.query(By.css('#ace-code-editor'));
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBeTruthy();
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBe(true);
});

it('if the component is loading a file from server, it should show the editor in a readonly state', () => {
comp.selectedFile = 'dummy';
comp.isLoading = true;
fixture.detectChanges();
const placeholder = debugElement.query(By.css('#no-file-selected'));
expect(placeholder).toBeNull();
expect(placeholder).toBe(null);
const aceEditor = debugElement.query(By.css('#ace-code-editor'));
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBeTruthy();
expect(comp.editor.getEditor().getReadOnly()).toBeTruthy();
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBe(true);
expect(comp.editor.getEditor().getReadOnly()).toBe(true);

comp.isLoading = false;
fixture.detectChanges();
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBeFalsy();
expect(comp.editor.getEditor().getReadOnly()).toBeFalsy();
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBe(false);
expect(comp.editor.getEditor().getReadOnly()).toBe(false);
});

it('if a file is selected and the component is not loading a file from server, the editor should be usable', () => {
comp.selectedFile = 'dummy';
comp.isLoading = false;
fixture.detectChanges();
const placeholder = debugElement.query(By.css('#no-file-selected'));
expect(placeholder).toBeNull();
expect(placeholder).toBe(null);
const aceEditor = debugElement.query(By.css('#ace-code-editor'));
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBeFalsy();
expect(comp.editor.getEditor().getReadOnly()).toBeFalsy();
expect(aceEditor.nativeElement.hasAttribute('hidden')).toBe(false);
expect(comp.editor.getEditor().getReadOnly()).toBe(false);
});

it('should not load the file from server on selected file change if the file is already in session', () => {
Expand All @@ -94,13 +94,13 @@ describe('CodeEditorAceComponent', () => {
triggerChanges(comp, { property: 'selectedFile', currentValue: selectedFile });
fixture.detectChanges();

expect(comp.isLoading).toBeTruthy();
expect(comp.isLoading).toBe(true);
expect(loadRepositoryFileStub).toHaveBeenCalledWith(selectedFile);
expect(initEditorAfterFileChangeSpy).not.toHaveBeenCalled();
loadFileSubject.next({ fileName: selectedFile, fileContent: 'lorem ipsum' });
fixture.detectChanges();

expect(comp.isLoading).toBeFalsy();
expect(comp.isLoading).toBe(false);
expect(initEditorAfterFileChangeSpy).toHaveBeenCalledWith();
});

Expand Down Expand Up @@ -188,7 +188,7 @@ describe('CodeEditorAceComponent', () => {
const displayFeedbacksSpy = jest.spyOn(comp, 'displayFeedbacks');
comp.onFileTextChanged('newFileContent');

expect(comp.editor.getEditor().getReadOnly()).toBeTruthy();
expect(comp.editor.getEditor().getReadOnly()).toBe(true);
expect(displayFeedbacksSpy).toHaveBeenCalledTimes(1);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { LocalStorageService, SessionStorageService } from 'ngx-webstorage';
import { CookieService } from 'ngx-cookie-service';
import { TranslateModule } from '@ngx-translate/core';
import { By } from '@angular/platform-browser';
import { DebugElement, SimpleChange } from '@angular/core';
import { Subject } from 'rxjs';
import { isEqual as _isEqual } from 'lodash-es';

import { AceEditorModule } from 'ng2-ace-editor';
import { CodeEditorRepositoryFileService, CodeEditorRepositoryService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service';
import { ArtemisTestModule } from '../../test.module';
import { FeatureToggleModule } from 'app/shared/feature-toggle/feature-toggle.module';
import { FeatureToggleService } from 'app/shared/feature-toggle/feature-toggle.service';
import { MockFeatureToggleService } from '../../helpers/mocks/service/mock-feature-toggle.service';

import { cartesianProduct } from 'app/shared/util/utils';
import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service';
import { CodeEditorConflictStateService } from 'app/exercises/programming/shared/code-editor/service/code-editor-conflict-state.service';
Expand All @@ -23,8 +17,11 @@ import { MockCodeEditorRepositoryFileService } from '../../helpers/mocks/service
import { MockCodeEditorRepositoryService } from '../../helpers/mocks/service/mock-code-editor-repository.service';
import { MockCookieService } from '../../helpers/mocks/service/mock-cookie.service';
import { CommitState, EditorState } from 'app/exercises/programming/shared/code-editor/model/code-editor.model';
import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
import { MockPipe } from 'ng-mocks';
import { MockModule } from 'ng-mocks';
import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service';
import { FeatureToggleDirective } from 'app/shared/feature-toggle/feature-toggle.directive';
import { FeatureToggleService } from 'app/shared/feature-toggle/feature-toggle.service';
import { MockFeatureToggleService } from '../../helpers/mocks/service/mock-feature-toggle.service';

describe('CodeEditorActionsComponent', () => {
let comp: CodeEditorActionsComponent;
Expand All @@ -35,10 +32,10 @@ describe('CodeEditorActionsComponent', () => {
let updateFilesStub: jest.SpyInstance;
let commitStub: jest.SpyInstance;

beforeEach(async () => {
return TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ArtemisTestModule, AceEditorModule, FeatureToggleModule],
declarations: [CodeEditorActionsComponent, MockPipe(ArtemisTranslatePipe)],
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ArtemisTestModule, MockModule(AceEditorModule)],
declarations: [CodeEditorActionsComponent, TranslatePipeMock, FeatureToggleDirective],
providers: [
{ provide: CodeEditorRepositoryService, useClass: MockCodeEditorRepositoryService },
{ provide: CodeEditorRepositoryFileService, useClass: MockCodeEditorRepositoryFileService },
Expand Down Expand Up @@ -69,8 +66,8 @@ describe('CodeEditorActionsComponent', () => {
fixture.detectChanges();
const submitButton = fixture.debugElement.query(By.css('#submit_button'));
const refreshButton = fixture.debugElement.query(By.css('#refresh_button'));
expect(submitButton).not.toBeNull();
expect(refreshButton).not.toBeNull();
expect(submitButton).not.toBe(null);
expect(refreshButton).not.toBe(null);
});

const enableCommitButtonCombinations = cartesianProduct([EditorState.UNSAVED_CHANGES, EditorState.CLEAN], [CommitState.UNCOMMITTED_CHANGES, CommitState.CLEAN], [false, true]);
Expand Down Expand Up @@ -183,24 +180,24 @@ describe('CodeEditorActionsComponent', () => {
commitStub.mockReturnValue(commitObservable);

const commitButton = fixture.debugElement.query(By.css('#submit_button'));
expect(commitButton.nativeElement.disabled).toBeFalsy();
expect(commitButton.nativeElement.disabled).toBe(false);

// start commit, wait for result
commitButton.nativeElement.click();
expect(commitStub).toHaveBeenNthCalledWith(1);
expect(comp.isBuilding).toBeFalsy();
expect(comp.isBuilding).toBe(false);
expect(comp.commitState).toEqual(CommitState.COMMITTING);

fixture.detectChanges();
expect(commitButton.nativeElement.disabled).toBeTruthy();
expect(commitButton.nativeElement.disabled).toBe(true);

// commit result mockReturnValue
commitObservable.next(null);
expect(comp.isBuilding).toBeTruthy();
expect(comp.isBuilding).toBe(true);
expect(comp.commitState).toEqual(CommitState.CLEAN);

fixture.detectChanges();
expect(commitButton.nativeElement.disabled).toBeFalsy();
expect(commitButton.nativeElement.disabled).toBe(false);
});

it('should commit if no unsaved changes exist and emit an error on error response', () => {
Expand All @@ -215,25 +212,25 @@ describe('CodeEditorActionsComponent', () => {
commitStub.mockReturnValue(commitObservable);

const commitButton = fixture.debugElement.query(By.css('#submit_button'));
expect(commitButton.nativeElement.disabled).toBeFalsy();
expect(commitButton.nativeElement.disabled).toBe(false);

// start commit, wait for result
commitButton.nativeElement.click();
expect(commitStub).toHaveBeenNthCalledWith(1);
expect(comp.isBuilding).toBeFalsy();
expect(comp.isBuilding).toBe(false);
expect(comp.commitState).toEqual(CommitState.COMMITTING);

fixture.detectChanges();
expect(commitButton.nativeElement.disabled).toBeTruthy();
expect(commitButton.nativeElement.disabled).toBe(true);

// commit result mockReturnValue an error
commitObservable.error('error!');
expect(comp.isBuilding).toBeFalsy();
expect(comp.isBuilding).toBe(false);
expect(comp.commitState).toEqual(CommitState.UNCOMMITTED_CHANGES);
expect(onErrorSpy).toHaveBeenNthCalledWith(1, 'commitFailed');

fixture.detectChanges();
expect(commitButton.nativeElement.disabled).toBeFalsy();
expect(commitButton.nativeElement.disabled).toBe(false);
});

it('should not commit if unsavedFiles exist, instead should save files with commit set to true', fakeAsync(() => {
Expand All @@ -250,7 +247,7 @@ describe('CodeEditorActionsComponent', () => {
saveChangedFilesStub.mockReturnValue(saveObservable);

const commitButton = fixture.debugElement.query(By.css('#submit_button'));
expect(commitButton.nativeElement.disabled).toBeFalsy();
expect(commitButton.nativeElement.disabled).toBe(false);

// unsaved changes exist, needs to save files first
commitButton.nativeElement.click();
Expand All @@ -270,11 +267,11 @@ describe('CodeEditorActionsComponent', () => {

tick();

expect(comp.isBuilding).toBeTruthy();
expect(comp.isBuilding).toBe(true);
expect(comp.commitState).toEqual(CommitState.CLEAN);

fixture.detectChanges();
expect(commitButton.nativeElement.disabled).toBeFalsy();
expect(commitButton.nativeElement.disabled).toBe(false);

fixture.destroy();
flush();
Expand Down
Loading

0 comments on commit e56f95f

Please sign in to comment.