Skip to content

Commit

Permalink
Issue Sunbird-inQuiry#42 feat: New Match Type Question Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Arpan Gupta committed Aug 7, 2023
1 parent c19a96e commit f82c884
Show file tree
Hide file tree
Showing 9 changed files with 495 additions and 264 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,39 @@
<i class="icon info circle ml-8" suiPopup popupDelay="500" popupText={{configService.labelConfig?.lbl?.optionsPopupText}}></i>
</div>
<div class="d-flex flex-w-wrap" *ngFor="let option of editorState.options; let i = index">
<div style="width: 100%; display: flex; gap: 2%;">
<div class="d-flex flex-w-wrap" style="justify-content: space-between; width: 80%;">
<div style="width: 40%;">
<div class="w-100 mb-24">
<div class="d-flex flex-w-wrap flex-jc-space-between w-100">
<div class="w-49">
<lib-ckeditor-tool
[setCharacterLimit]="setCharacterLimit" (editorDataOutput)="option.leftOption= $event.body; editorDataHandler($event);"
[editorDataInput]="option.leftOption" class="ckeditor-tool__option mb-10"
[class.mb-5]="showFormError && option.leftOption.length > setCharacterLimit">
[setCharacterLimit]="setCharacterLimit" (editorDataOutput)="option.left= $event.body; editorDataHandler($event);"
[editorDataInput]="option.left" class="ckeditor-tool__option mb-10"
[class.mb-5]="showFormError && option.left.length > setCharacterLimit">
</lib-ckeditor-tool>
<label *ngIf="option.leftOption.length > setCharacterLimit" class="ui basic red error label pt-1">
<label *ngIf="option.left.length > setCharacterLimit" class="ui basic red error label pt-1">
{{configService.labelConfig?.lbl?.reduceSize}}</label>
<label *ngIf="showFormError && (option.leftOption === undefined || option.leftOption === '')"
<label *ngIf="showFormError && (option.left === undefined || option.left === '')"
class="sb-color-error fs-0-785">{{configService.labelConfig?.lbl?.fillThisOption}}</label>
</div>
<div style="width: 40%;">
<div class="w-49">
<lib-ckeditor-tool
[setCharacterLimit]="setCharacterLimit" (editorDataOutput)="option.rightOption = $event.body; editorDataHandler($event);"
[editorDataInput]="option.rightOption" class="ckeditor-tool__option mb-10"
[setCharacterLimit]="setCharacterLimit" (editorDataOutput)="option.right = $event.body; editorDataHandler($event);"
[editorDataInput]="option.right" class="ckeditor-tool__option mb-10"
[class.mb-5]="showFormError && option.righOption.length > setCharacterLimit">
</lib-ckeditor-tool>
<label *ngIf="option.rightOption.length > setCharacterLimit" class="ui basic red error label pt-1">
<label *ngIf="option.right.length > setCharacterLimit" class="ui basic red error label pt-1">
{{configService.labelConfig?.lbl?.reduceSize}}</label>
<label *ngIf="showFormError && (option.rightOption === undefined || option.rightOption === '')"
<label *ngIf="showFormError && (option.right === undefined || option.right === '')"
class="sb-color-error fs-0-785">{{configService.labelConfig?.lbl?.fillThisOption}}</label>
</div>
</div>
<div style="height: 100%; width: 4%;">
<button [disabled]="editorState.options.length < 3" class="" style="height: 30%; width: 100%;"
<div>
<button
class="sb-btn sb-btn-xs sb-left-icon-btn text-inherit b-0 bg-none no-hover p-0 mb-10 mt-10 right"
[disabled]="editorState.options.length < 3"
(click)="editorState.deleteOptions(i);editorDataHandler($event);"
libTelemetryInteract
[telemetryInteractEdata]="telemetryService.getTelemetryInteractEdata('delete_option','click','submit',telemetryService.telemetryPageId)">
<i class="icon close"></i>
<i class="icon trash outline fs-1-286 pull-left mr-0"></i><span class="sb-line-height-24">{{configService.labelConfig?.button_labels?.delete_pair_btn_label}}</span>
</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.b-0{
border: 0 !important;
}

.bg-none{
background-color: transparent !important;

&:hover,
&:focus {
background-color: transparent !important;
}
}

.w-49{
width: 49%;
max-width: 49%;
}

.sb-line-height-24 {
line-height: 24px;
}

.right{
float: right;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
export const mockOptionData = {
editorOptionData: {
question: "<p>Match the following with appropriate answer?</p>",
options: [
{
left: "<p>Lotus</p>",
right: "<p>Flower</p>",
},
{
left: "<p>Mango</p>",
right: "<p>Fruit</p>",
},
],
templateId: "mtf-vertical",
correctMatchPair: [{ "0": 0 }, { "1": 1 }],
numberOfOptions: 4,
},
prepareMtfBody: {
templateId: "default",
name: "Match The Following Question",
responseDeclaration: {
response1: {
cardinality: "multiple",
type: "map",
correctResponse: {
value: [
{
"0": 0,
},
{
"1": 1,
},
],
},
mapping: [
{
value: {
"0": 0,
},
score: 2,
},
{
value: {
"1": 1,
},
score: 2,
},
],
},
},
interactionTypes: ["match"],
interactions: {
response1: {
type: "match",
options: {
left: [
{
label: "<p>Lotus</p>",
value: 0,
},
{
label: "<p>Mango</p>",
value: 1,
},
],
right: [
{
label: "<p>Flower</p>",
value: 0,
},
{
label: "<p>Fruit</p>",
value: 1,
},
],
},
},
},
editorState: {
options: {
left: [
{
value: {
body: "<p>Lotus</p>",
value: 0,
},
},
{
value: {
body: "<p>Mango</p>",
value: 1,
},
},
],
right: [
{
value: {
body: "<p>Flower</p>",
value: 0,
},
},
{
value: {
body: "<p>Fruit</p>",
value: 1,
},
},
],
},
},
qType: "MTF",
primaryCategory: "Match The Following Question",
},
};
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import { TelemetryInteractDirective } from '../../directives/telemetry-interact/telemetry-interact.directive';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { FormsModule } from '@angular/forms';
import { MatchComponent } from './match.component';
import { CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import { mockOptionData } from './match.component.spec.data';
import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange} from '@angular/core';
import { ConfigService } from '../../services/config/config.service';
import { SuiModule } from 'ng2-semantic-ui-v9';
import { TreeService } from '../../services/tree/tree.service';
import { EditorTelemetryService } from '../../services/telemetry/telemetry.service';


describe('OptionsComponent', () => {
describe('MatchComponent', () => {
let component: MatchComponent;
let fixture: ComponentFixture<MatchComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, FormsModule, SuiModule],
imports: [HttpClientTestingModule],
declarations: [MatchComponent, TelemetryInteractDirective],
providers: [ConfigService, TreeService, EditorTelemetryService,],
providers: [ConfigService, EditorTelemetryService,],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
Expand All @@ -26,10 +24,117 @@ describe('OptionsComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(MatchComponent);
component = fixture.componentInstance;
component.editorState = mockOptionData.editorOptionData;
// fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it("#ngOnInit() should call editorDataHandler on ngOnInit", () => {
component.editorState = mockOptionData.editorOptionData;
spyOn(component, "editorDataHandler");
component.ngOnInit();
expect(component.editorDataHandler).toHaveBeenCalled();
});

it("should not set #templateType when creating new question", () => {
component.editorState = {};
spyOn(component, "editorDataHandler");
component.ngOnInit();
expect(component.templateType).toEqual("mtf-horizontal");
});

it("should set #templateType when updating an existing question", () => {
component.editorState = mockOptionData.editorOptionData;
spyOn(component, "editorDataHandler");
component.ngOnInit();
expect(component.templateType).toEqual("mtf-vertical");
});

it("ngOnChanges should not call editorDataHandler", () => {
spyOn(component, "editorDataHandler").and.callFake(() => {});
spyOn(component, "ngOnChanges").and.callThrough();
component.ngOnChanges({
maxScore: new SimpleChange(undefined, 4, true),
});
expect(component.editorDataHandler).not.toHaveBeenCalled();
});

it("ngOnChanges should call editorDataHandler", () => {
spyOn(component, "editorDataHandler").and.callFake(() => {});
spyOn(component, "ngOnChanges").and.callThrough();
component.ngOnChanges({
maxScore: new SimpleChange(1, 2, false),
});
expect(component.editorDataHandler).toHaveBeenCalled();
});

it('#editorDataHandler() should emit option data', () => {
spyOn(component, 'prepareMtfBody').and.callThrough();
spyOn(component.editorDataOutput, 'emit').and.callThrough();
component.editorState = mockOptionData.editorOptionData;
component.editorState.correctMatchPair = [{ "0": 0 }, { "1": 1 }];
component.editorDataHandler();
expect(component.prepareMtfBody).toHaveBeenCalledWith(mockOptionData.editorOptionData);
expect(component.editorDataOutput.emit).toHaveBeenCalled();
});

it("#prepareMtfBody() should return expected mtf option data for MTF", () => {
component.maxScore = 4;
spyOn(component, 'setMapping').and.callThrough();
spyOn(component, "getResponseDeclaration").and.callThrough();
spyOn(component, "getInteractions").and.callThrough();
const result = component.prepareMtfBody(mockOptionData.editorOptionData);
expect(component.getResponseDeclaration).toHaveBeenCalledWith(
mockOptionData.editorOptionData
);
expect(component.getInteractions).toHaveBeenCalledWith(
mockOptionData.editorOptionData.options
);
});

it('#getInteractions should return expected interactions', () => {
spyOn(component, 'getInteractions').and.callThrough();
const result = component.getInteractions(mockOptionData.editorOptionData.options);
expect(result).toEqual(mockOptionData.prepareMtfBody.interactions);
})

it('#setMapping should set mapping', () => {
spyOn(component, 'setMapping').and.callThrough();
component.editorState = mockOptionData.editorOptionData;
component.editorState.correctMatchPair = mockOptionData.editorOptionData.correctMatchPair;
component.maxScore = 4;
component.setMapping();
expect(component.mapping).toEqual(mockOptionData.prepareMtfBody.responseDeclaration.response1.mapping);
})

it('#getOutcomeDeclaration should return expected outcomeDeclaration', () => {
component.maxScore = 4;
spyOn(component, 'getOutcomeDeclaration').and.callThrough();
const outcomeDeclaration = component.getOutcomeDeclaration();
expect(outcomeDeclaration.maxScore.cardinality).toEqual('multiple');
expect(outcomeDeclaration.maxScore.defaultValue).toEqual(4);
})

it('#getResponseDeclaration should return expected responseDeclaration', () => {
component.mapping = [
{
value: {
"0": 0,
},
score: 2,
},
{
value: {
"1": 1,
},
score: 2,
},
];
spyOn(component, "getResponseDeclaration").and.callThrough();
const responseDeclaration = component.getResponseDeclaration(mockOptionData.editorOptionData);
expect(responseDeclaration.response1.cardinality).toEqual('multiple');
})
});
Loading

0 comments on commit f82c884

Please sign in to comment.