Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Introduce allowHTML option to allow people to disable injecting HTML into choices. #984

Merged
merged 9 commits into from
Dec 26, 2021
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Or include Choices directly:
removeItems: true,
removeItemButton: false,
editItems: false,
allowHTML: true
duplicateItemsAllowed: true,
delimiter: ',',
paste: true,
Expand Down Expand Up @@ -314,6 +315,14 @@ Pass an array of objects:

**Usage:** Whether a user can edit items. An item's value can be edited by pressing the backspace.

### allowHTML

**Type:** `Boolean` **Default:** `true`

**Input types affected:** `text`, `select-one`, `select-multiple

**Usage:** Whether HTML should be shown properly when showing choices. (Can be used to perform XSS attacks if not disabled or handled correctly)

### duplicateItemsAllowed

**Type:** `Boolean` **Default:** `true`
Expand Down
88 changes: 67 additions & 21 deletions cypress/integration/text.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
describe('Choices - text element', () => {
beforeEach(() => {
cy.visit('/text');
cy.visit('/text', {
onBeforeLoad(win) {
cy.stub(win.console, 'warn').as('consoleWarn');
},
});
});

describe('scenarios', () => {
Expand All @@ -17,7 +21,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--multiple .choices__item')
.last()
.should($el => {
.should(($el) => {
expect($el).to.contain(textInput);
});
});
Expand All @@ -42,7 +46,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
`Press Enter to add "${textInput}"`,
Expand Down Expand Up @@ -74,7 +78,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=edit-items]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.data('value')).to.equal(`${textInput}-edited`);
});
});
Expand All @@ -90,7 +94,7 @@ describe('Choices - text element', () => {
it('highlights all items', () => {
cy.get('[data-test-hook=edit-items]')
.find('.choices__list--multiple .choices__item')
.each($choice => {
.each(($choice) => {
expect($choice.hasClass('is-highlighted')).to.equal(true);
});
});
Expand Down Expand Up @@ -124,7 +128,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=remove-button]')
.find('.choices__list--multiple')
.children()
.should($items => {
.should(($items) => {
expect($items.length).to.equal(1);
});

Expand All @@ -137,7 +141,7 @@ describe('Choices - text element', () => {

cy.get('[data-test-hook=remove-button]')
.find('.choices__list--multiple .choices__item')
.should($items => {
.should(($items) => {
expect($items.length).to.equal(0);
});
});
Expand All @@ -152,7 +156,7 @@ describe('Choices - text element', () => {

cy.get('[data-test-hook=remove-button]')
.find('.choices__input[hidden]')
.then($input => {
.then(($input) => {
expect($input.val()).to.not.contain(textInput);
});
});
Expand All @@ -175,7 +179,7 @@ describe('Choices - text element', () => {
.find('.choices__list--multiple')
.first()
.children()
.should($items => {
.should(($items) => {
expect($items.length).to.equal(1);
});
});
Expand All @@ -185,7 +189,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=unique-values]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
'Only unique values can be added',
Expand All @@ -212,7 +216,7 @@ describe('Choices - text element', () => {
.find('.choices__list--multiple')
.first()
.children()
.should($items => {
.should(($items) => {
expect($items.length).to.equal(inputLimit);
});
});
Expand All @@ -222,7 +226,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=input-limit]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
`Only ${inputLimit} values can be added`,
Expand All @@ -245,7 +249,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=add-item-filter]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(input);
});
});
Expand All @@ -261,7 +265,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=add-item-filter]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
'Only values matching specific conditions can be added',
Expand All @@ -283,7 +287,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.data('value')).to.equal(`before-${textInput}-after`);
});
});
Expand All @@ -292,7 +296,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text()).to.not.contain(`before-${textInput}-after`);
expect($choice.text()).to.contain(textInput);
});
Expand All @@ -319,21 +323,21 @@ describe('Choices - text element', () => {
it('pre-populates choices', () => {
cy.get('[data-test-hook=prepopulated]')
.find('.choices__list--multiple .choices__item')
.should($choices => {
.should(($choices) => {
expect($choices.length).to.equal(2);
});

cy.get('[data-test-hook=prepopulated]')
.find('.choices__list--multiple .choices__item')
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Josh Johnson');
});

cy.get('[data-test-hook=prepopulated]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Joe Bloggs');
});
});
Expand All @@ -355,11 +359,53 @@ describe('Choices - text element', () => {
});
});

describe('allow html', () => {
mason-rogers marked this conversation as resolved.
Show resolved Hide resolved
describe('is undefined', () => {
it('logs a deprecation warning', () => {
cy.get('@consoleWarn').should(
'be.calledOnceWithExactly',
'Deprecation warning: allowHTML in the future will be defaulted to false. You must explicitly set it to true to properly display html tags in choices.',
);
});

it('does not show html as text', () => {
cy.get('[data-test-hook=allowhtml-undefined]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Mason Rogers');
});
});
});

describe('set to true', () => {
it('does not show html as text', () => {
cy.get('[data-test-hook=allowhtml-true]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Mason Rogers');
});
});
});

describe('set to false', () => {
it('shows html as text', () => {
cy.get('[data-test-hook=allowhtml-false]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('<b>Mason Rogers</b>');
});
});
});
});

describe('within form', () => {
describe('inputting item', () => {
describe('on enter key', () => {
it('does not submit form', () => {
cy.get('[data-test-hook=within-form] form').then($form => {
cy.get('[data-test-hook=within-form] form').then(($form) => {
$form.submit(() => {
// this will fail the test if the form submits
throw new Error('Form submitted');
Expand All @@ -374,7 +420,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=within-form]')
.find('.choices__list--multiple .choices__item')
.last()
.should($el => {
.should(($el) => {
expect($el).to.contain(textInput);
});
});
Expand Down
Loading