Skip to content

Commit

Permalink
feat: add rubric author tool (#7)
Browse files Browse the repository at this point in the history
A short term solution adding a utiliy method to insert the rubric author
tool into an item config. This will be deprecated  later when we do a
 review of handling rubrics & other tools.
  • Loading branch information
evaneus authored Jul 11, 2019
1 parent b459ad9 commit bd1847a
Show file tree
Hide file tree
Showing 12 changed files with 338 additions and 64 deletions.
49 changes: 0 additions & 49 deletions src/__tests__/rubric-defaults.spec.ts

This file was deleted.

95 changes: 95 additions & 0 deletions src/__tests__/rubric-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { addRubric, addPackageToContent } from '../rubric-utils';
import { PieContent, PieModel } from '../interface';
import cloneDeep from 'lodash/cloneDeep'



describe('rubric utils', () => {

let pieContent:PieContent, noRubric:PieContent;
let rubricModel: PieModel;
beforeEach(() => {
pieContent = {
id: '1',
elements: {
'pie-rubric': '@pie-element/rubric@latest'
},
models: [
{
id: 'x',
element: 'pie-rubric'
}
],
markup: 'markup here'
};

noRubric = {
id: '1',
elements: {
'something-else': '@pie-element/something-else@latest'
},
models: [
{
id: 'x',
element: 'something-else'
}
],
markup: 'markup here'
};

rubricModel = {
"id": "rubric",
"element": "pie-rubric",
"points": [
"level 1",
"level 2",
"level 3",
"level 4"
],
"maxPoints": 4,
"excludeZero": false
}


});

describe('add rubric to markup', () => {
it('adds rubric to markup', () => {
const handled = addRubric(pieContent);
expect(handled.markup).toMatch(/pie-rubric/);
});

it('do nothing if in markup', () => {
const content = {
...pieContent,
markup: '<pie-rubric id="x"></pie-rubric>'
};
const handled = addRubric(content);
expect(handled).toEqual(content);
});

it('do nothing if no rubric', () => {
const handled = addRubric(noRubric);
expect(handled).toEqual(noRubric);
});
});

describe('add rubric to model', () => {
it('adds a rubric to a model', () => {
addPackageToContent(noRubric, '@pie-element/rubric', rubricModel);
expect(Object.values(noRubric.elements)).toContain('@pie-element/rubric')
});

it('does not modify if rubric already there', () => {
const copy = cloneDeep(pieContent);
addPackageToContent(pieContent, '@pie-element/rubric', rubricModel);
expect(copy).toEqual(pieContent);
});

it('works with semver', () => {
addPackageToContent(noRubric, '@pie-element/rubric@latest', rubricModel);
expect(Object.values(noRubric.elements)).toContain('@pie-element/rubric@latest')
});
});

});
12 changes: 12 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export namespace Components {
*/
'addPreview': boolean;
/**
* If set the player will add a rubric authoring interaction to the config
*/
'addRubric': boolean;
/**
* Utility method to add a `@pie-element/rubric` section to an item config when creating an item should be used before setting the config.
*/
'addRubricToConfig': (config: ItemConfig, rubricModel?: any) => Promise<ItemConfig>;
/**
* The Pie config model.
*/
'config': ItemConfig;
Expand All @@ -38,6 +46,10 @@ export namespace Components {
*/
'addPreview'?: boolean;
/**
* If set the player will add a rubric authoring interaction to the config
*/
'addRubric'?: boolean;
/**
* The Pie config model.
*/
'config'?: ItemConfig;
Expand Down
7 changes: 7 additions & 0 deletions src/components/__tests__/mockPieCloudResponse.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class InlineChoiceConfig extends MockConfig {}
class MathInline extends MockElement {}
class MathInlineConfig extends MockConfig {}
class Passage extends MockElement {}
class Rubric extends MockElement {}
class RubricConfig extends MockConfig {}



Expand All @@ -81,6 +83,11 @@ window['pie'] = {
Configure: MathInlineConfig,
controller
},
'@pie-element/rubric': {
Element: Rubric,
Configure: RubricConfig,
controller
},
'@pie-element/passage': {
Element: Passage
}
Expand Down
35 changes: 29 additions & 6 deletions src/components/pie-author/__tests__/pie-author.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { newE2EPage, E2EElement, E2EPage } from '@stencil/core/testing';
import { setupInterceptPieCloud } from '../../__tests__/util';
import { simplePieMock, multipleChoiceItem, inlineChoiceItem } from '../../__mock__/config';
import cloneDeep from 'lodash/cloneDeep';

describe('pie-author', () => {
let pie;
let page: E2EPage, pieAuthor: E2EElement;
let pieMock
beforeEach(async () => {
pie = '@pie-element/multiple-choice';
page = await newE2EPage()
page = await newE2EPage();
pieMock = cloneDeep(simplePieMock);

});

it('renders', async () => {
Expand All @@ -21,7 +25,7 @@ describe('pie-author', () => {
await page.setContent('<pie-author config="evan"></pie-author>');
pieAuthor = await page.find('pie-author');
await setupInterceptPieCloud(page, pie);
pieAuthor.setProperty('config', simplePieMock)
pieAuthor.setProperty('config', pieMock)
await page.waitForChanges();
const el = await page.waitForSelector('pie-author');
expect(el).toBeDefined();
Expand All @@ -35,7 +39,7 @@ describe('pie-author', () => {
await page.setContent('<pie-author config="evan"></pie-author>');
pieAuthor = await page.find('pie-author');
await setupInterceptPieCloud(page, pie);
pieAuthor.setProperty('config', simplePieMock)
pieAuthor.setProperty('config', pieMock)
const spy = await page.spyOnEvent('modelLoaded');
await page.waitForChanges();
expect(spy).toHaveReceivedEvent();
Expand All @@ -46,7 +50,7 @@ describe('pie-author', () => {
await page.setContent('<pie-author></pie-author>');
pieAuthor = await page.find('pie-author');
await setupInterceptPieCloud(page, pie);
const emptyItem = simplePieMock;
const emptyItem = pieMock;
emptyItem.models = null;
await page.$eval('pie-author',
(elm: any, prop) => {
Expand Down Expand Up @@ -74,7 +78,7 @@ describe('pie-author', () => {
return elm;
},
{
config: simplePieMock,
config: pieMock,
configSettings: {'@pie-element/multiple-choice': { "foo": "bar"} }
}
);
Expand All @@ -88,6 +92,26 @@ describe('pie-author', () => {
expect(configProp.foo).toEqual("bar");
});

it('add a rubric before adding config', async () => {
await page.setContent('<pie-author></pie-author>');
pieAuthor = await page.find('pie-author');
await setupInterceptPieCloud(page, pie);
const rubricAdded = await pieAuthor.callMethod('addRubricToConfig', pieMock, {foo: 'bar'});
expect(Object.values(rubricAdded.elements)).toContain('@pie-element/rubric');

const tagName = Object.keys(rubricAdded.elements)[1];

pieAuthor.setProperty('config', rubricAdded);
await page.waitForChanges();
await page.waitForSelector(`pie-author ${tagName}-config:defined`);
const rubricModel = await page.$eval(
`pie-author ${tagName}-config`,
el => (el as any).model
);
expect(rubricModel.foo).toEqual('bar');

});

// TODO request intercetpion needs to be updated for this to work
it.skip('can switch items', async() => {
await page.setContent('<pie-author config="evan"></pie-author>');
Expand All @@ -102,7 +126,6 @@ describe('pie-author', () => {
);
expect(pieModel.element).toEqual('pie-multiple-choice');

console.log(`got past first item`)
await setupInterceptPieCloud(page, `@pie-element/inline-choice`);
pieAuthor.setProperty('config', inlineChoiceItem);
await page.waitForChanges();
Expand Down
43 changes: 40 additions & 3 deletions src/components/pie-author/pie-author.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Component, Element, Prop, State, Watch, Event, EventEmitter } from '@stencil/core';
import { PieContent, ItemConfig, PieElement } from '../../interface';
import { Component, Element, Prop, State, Watch, Event, EventEmitter, Method } from '@stencil/core';
import { PieContent, ItemConfig, PieElement, PieModel } from '../../interface';
import { PieLoader } from '../../pie-loader';
import { pieContentFromConfig } from '../../utils/utils';
import parseNpm from 'parse-package-name';
import { ModelUpdatedEvent } from '@pie-framework/pie-configure-events';
import _isEqual from 'lodash/isEqual';
import { addPackageToContent, addRubric } from '../../rubric-utils';

/**
* Pie Author will load a Pie Content model for authoring.
Expand All @@ -18,6 +19,13 @@ import _isEqual from 'lodash/isEqual';
export class Author {
@Prop({ context: 'document' }) doc!: Document;


/**
* If set the player will add a rubric authoring interaction to the config
*/
@Prop() addRubric: boolean;


/**
* Adds a preview view which will render the content in another tab as it may appear to a student or instructor.
*/
Expand Down Expand Up @@ -161,7 +169,6 @@ export class Author {
await this.afterRender();
await this.updateModels();
this.el.addEventListener(ModelUpdatedEvent.TYPE, (e:ModelUpdatedEvent) => {
console.log(`got event ${e.detail}`)
// set the internal model
// emit a content-item level event with the model
if (this.pieContentModel && e.update) {
Expand Down Expand Up @@ -197,6 +204,36 @@ export class Author {
}
}

/**
* Utility method to add a `@pie-element/rubric` section to an item config when creating an item should be used before setting the config.
*
* @deprecated this method is for temporary use, will be removed at next major release
*
* @param config the item config to mutate
* @param rubricModel
*/
@Method()
async addRubricToConfig(config: ItemConfig, rubricModel?) {
if (!rubricModel) {
rubricModel = {
"id": "rubric",
"element": "pie-rubric",
"points": [
"",
"",
"",
""
],
"maxPoints": 4,
"excludeZero": false
};
}
const configPieContent = pieContentFromConfig(config);
addPackageToContent(configPieContent, '@pie-element/rubric', rubricModel as PieModel);
addRubric(configPieContent);
return config;
}

render() {
if (this.pieContentModel && this.pieContentModel.markup) {
if (this.addPreview) {
Expand Down
21 changes: 21 additions & 0 deletions src/components/pie-author/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The class `pie-loading` will be added to the element while assets are being load
| Property | Attribute | Description | Type | Default |
| ---------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | ----------- |
| `addPreview` | `add-preview` | Adds a preview view which will render the content in another tab as it may appear to a student or instructor. | `boolean` | `false` |
| `addRubric` | `add-rubric` | If set the player will add a rubric authoring interaction to the config | `boolean` | `undefined` |
| `config` | -- | The Pie config model. | `AdvancedItemConfig \| PieContent` | `undefined` |
| `configSettings` | -- | To customize the standard behaviour provided by interaction configuration views you can provide settings key-ed by the package name. e.g. `{ '@pie-element/inline-choice': { promptLabel: 'Item Stem' } }` The settings that are configurable for each authoring view are documented in the `@package-name/docs` folder for each package. | `{ [packageName: string]: Object; }` | `undefined` |

Expand All @@ -28,6 +29,26 @@ The class `pie-loading` will be added to the element while assets are being load
| `modelUpdated` | Emmitted when the model for the content has been updated within the ui due to user action. | `CustomEvent<void>` |


## Methods

### `addRubricToConfig(config: ItemConfig, rubricModel?: any) => Promise<ItemConfig>`

Utility method to add a `@pie-element/rubric` section to an item config when creating an item should be used before setting the config.

#### Parameters

| Name | Type | Description |
| ------------- | ---------------------------------- | ------------------------- |
| `config` | `AdvancedItemConfig \| PieContent` | the item config to mutate |
| `rubricModel` | `any` | |

#### Returns

Type: `Promise<ItemConfig>`




----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
Loading

0 comments on commit bd1847a

Please sign in to comment.