Skip to content

Commit

Permalink
Merge branch 'master' into JSUI-2786
Browse files Browse the repository at this point in the history
  • Loading branch information
btaillon-coveo committed Oct 15, 2020
2 parents 8d2930f + 4306b31 commit a48171b
Show file tree
Hide file tree
Showing 80 changed files with 3,856 additions and 395 deletions.
4 changes: 1 addition & 3 deletions accessibilityTest/AccessibilityCategoryFacet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ export const AccessibilityCategoryFacet = () => {
describe('after focusing on the search button', () => {
function hideFocusedSearchFacetValueStyle() {
const focusedClass = 'coveo-facet-search-current-result';
$$(getRoot())
.findClass(focusedClass)[0]
.classList.remove(focusedClass);
$$(getRoot()).findClass(focusedClass)[0].classList.remove(focusedClass);
}

beforeEach(async done => {
Expand Down
108 changes: 108 additions & 0 deletions accessibilityTest/AccessibilitySmartSnippet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import * as axe from 'axe-core';
import { Dom, SmartSnippet, Component, $$, IQuerySuccessEventArgs } from 'coveo-search-ui';
import { getRoot, afterDeferredQuerySuccess, getResultsColumn, waitUntilSelectorIsPresent } from './Testing';

export const AccessibilitySmartSnippet = () => {
describe('SmartSnippet', () => {
function fakeNextQuestionAnswer() {
$$(getRoot()).one('querySuccess', (_, e: IQuerySuccessEventArgs) => {
e.results.questionAnswer = {
question: 'Getting Query Suggestions',
answerSnippet:
'<p>You can request basic query expression (q) completions from a Coveo Machine Learning (Coveo ML) Query Suggestions (QS) model by sending a GET or POST HTTP request to https://platform.cloud.coveo.com/rest/search/v2/querySuggest (or https://cloudplatform.coveo.com/rest/search/querySuggest on Coveo Cloud V1).</p> <p>The Search API query suggestion route supports several parameters which you can include either in the query string of a GET request, or in the JSON body of a POST request (see QS Parameters).</p> <div class="box note"> \n <p>When using an OAuth2 token to authenticate a GET or POST HTTP request to the Search API query suggestion route, you must specify the unique identifier of the target Coveo Cloud organization by including the organizationId argument in the query string of your request.</p> \n</div> <div class="box examples"> \n <ol> \n <li> <p>Requesting query suggestions using the GET method:</p> \n <div class="language-http highlighter-rouge"> \n <div class="highlight">\n GET https://platform.cloud.coveo.com/rest/search/v2/querySuggest?locale=en&amp;q=twa&amp;searchHub=BookstoreSearch HTTP/1.1 &nbsp; Accept: application/json Authorization: Bearer **********-****-****-****-************ \n </div> \n </div> </li> \n <li> <p>Requesting query suggestions using the POST method:</p> \n <div class="language-http highlighter-rouge"> \n <div class="highlight">\n POST https://platform.cloud.coveo.com/rest/search/v2/querySuggest HTTP/1.1 &nbsp; Content-Type: application/json Accept: application/json Authorization: Bearer **********-****-****-****-************ \n </div> \n </div> <p>Payload</p> \n <div class="language-json highlighter-rouge"> \n <div class="highlight">\n { "locale": "en", "q": "twa", "searchHub": "BookstoreSearch" } \n </div> \n </div> \n <div class="box success"> \n <p><strong>200 OK response body (excerpt)</strong></p> \n <div class="language-json highlighter-rouge"> \n <div class="highlight">\n { "completions": [ { "executableConfidence": 1, "expression": "mark twain", "highlighted": "[mark] {twa}[in]", "score": 14.525258530973204 }, { "executableConfidence": 0.6666666666666666, "expression": "[wes]{twa}[rd] [ho]", "highlighted": "", "score": 8.50548085208594 }, { "executableConfidence": 0.5, "expression": "hot water music", "highlighted": "[hot] (wat)[er] [music]", "score": 7.107770631785241 }, ... ] } \n </div> \n </div> \n </div> </li> \n </ol> \n</div> <div class="box notes"> \n <ul> \n <li> <p>If the query suggestion request is routed to a query pipeline with no associated Coveo ML QS model, the request will return an empty completions array.</p> </li> \n <li> <p>In a completions array item:</p> \n <ul> \n <li> <p>The score property value only has relative significance within the same completions array.</p> <p>For instance, a suggestion with a score of 14.811407079917723 in the completions array of response <strong>A</strong> isn’t necessarily less relevant than a suggestion with a score of 24.325728875625282 in the completions array of response <strong>B</strong>.</p> </li> \n <li> <p>The highlighted property uses the following logic:</p> \n <ul> \n <li> <p>Characters between curly braces (e.g., {cat}) indicate an exact match with q.</p> </li> \n <li> <p>Characters between square braces (e.g., [cher]) indicate completions.</p> </li> \n <li> <p>Characters between parentheses (e.g., (act)) indicate corrections to q.</p> </li> \n </ul> </li> \n <li> <p>The executableConfidence property contains a floating-point value between 0 and 1 indicating how “convinced” Coveo ML is that performing a query with this suggestion as a basic query expression will return relevant results. The threshold from which Coveo ML considers a query suggestion executable is 0.8.</p> </li> \n </ul> </li> \n </ul> \n</div>',
documentId: {
contentIdKey: 'permanentid',
contentIdValue: e.results.results[0].raw.permanentid
},
score: 0.471416,
relatedQuestions: []
};
});
}

function getFirstChild(className: string) {
return smartSnippetElement.findClass(className)[0];
}

let smartSnippetElement: Dom;
beforeEach(async done => {
smartSnippetElement = $$('div', { className: Component.computeCssClassName(SmartSnippet) });
fakeNextQuestionAnswer();
getResultsColumn().appendChild(smartSnippetElement.el);
await afterDeferredQuerySuccess();
done();
});

it('should be accessible', async done => {
const axeResults = await axe.run(smartSnippetElement.el);
expect(axeResults).toBeAccessible();
done();
});

describe('after responding "Yes" to "Was this helpful?"', () => {
beforeEach(() => {
getFirstChild('coveo-user-feedback-banner-yes-button').click();
});

it('should be accessible', async done => {
const axeResults = await axe.run(smartSnippetElement.el);
expect(axeResults).toBeAccessible();
done();
});
});

describe('after responding "No" to "Was this helpful?"', () => {
beforeEach(() => {
getFirstChild('coveo-user-feedback-banner-no-button').click();
});

it('should be accessible', async done => {
const axeResults = await axe.run(smartSnippetElement.el);
expect(axeResults).toBeAccessible();
done();
});

describe('after pressing "Explain why"', () => {
let modalContainer: HTMLElement;
beforeEach(async done => {
getFirstChild('coveo-user-feedback-banner-explain-why').click();
modalContainer = await waitUntilSelectorIsPresent<HTMLElement>(document.body, '.coveo-user-explanation-modal');
done();
});

it('should be accessible', async done => {
const axeResults = await axe.run(modalContainer);
expect(axeResults).toBeAccessible();
done();
});

it('should be accessible after selecting other', async done => {
modalContainer.querySelector<HTMLInputElement>('#coveo-reason-other').click();
const axeResults = await axe.run(modalContainer);
expect(axeResults).toBeAccessible();
done();
});

it('should be accessible after selecting other and focusing the details', async done => {
modalContainer.querySelector<HTMLInputElement>('#coveo-reason-other').click();
modalContainer.querySelector<HTMLTextAreaElement>('#coveo-user-explanation-modal-details').focus();
const axeResults = await axe.run(modalContainer);
expect(axeResults).toBeAccessible();
done();
});
});
});

describe('after pressing show more', () => {
beforeEach(() => {
getFirstChild('coveo-height-limiter-button').click();
});

it('should be accessible', async done => {
const axeResults = await axe.run(smartSnippetElement.el);
expect(axeResults).toBeAccessible();
done();
});
});
});
};
83 changes: 83 additions & 0 deletions accessibilityTest/AccessibilitySmartSnippetSuggestions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as axe from 'axe-core';
import { Dom, SmartSnippetSuggestions, Component, $$, IQuerySuccessEventArgs } from 'coveo-search-ui';
import { getRoot, afterDeferredQuerySuccess, getResultsColumn } from './Testing';

export const AccessibilitySmartSnippetSuggestions = () => {
describe('SmartSnippetSuggestions', () => {
function fakeNextQuestionAnswer() {
$$(getRoot()).one('querySuccess', (_, e: IQuerySuccessEventArgs) => {
e.results.questionAnswer = {
question: 'Getting Query Suggestions',
answerSnippet:
'<p>You can request <a class="coveo-glossary-entry-link" href="/en/178/">basic query expression (q)</a> completions from a <a class="coveo-glossary-entry-link" href="/en/188/">Coveo Machine Learning (Coveo ML)</a> <a class="coveo-glossary-entry-link" href="/en/1015/">Query Suggestions (QS)</a> <a class="coveo-glossary-entry-link" href="/en/1012/">model</a> by sending a GET or POST HTTP request to https://platform.cloud.coveo.com/rest/search/v2/querySuggest (or https://cloudplatform.coveo.com/rest/search/querySuggest on Coveo Cloud V1).</p> <p>The Search API query suggestion route supports several parameters which you can include either in the query string of a GET request, or in the JSON body of a POST request (see <a href="#qs-parameters">QS Parameters</a>).</p> <div class="box note"> \n <p>When using an OAuth2 token to authenticate a GET or POST HTTP request to the Search API query suggestion route, you must specify the unique identifier of the target <a class="coveo-glossary-entry-link" href="/en/185/">Coveo Cloud organization</a> by including the organizationId argument in the query string of your request.</p> \n</div> <div class="box examples"> \n <ol> \n <li> <p>Requesting query suggestions using the GET method:</p> \n <div class="language-http highlighter-rouge"> \n <div class="highlight">\n GET https://platform.cloud.coveo.com/rest/search/v2/querySuggest?locale=en&amp;q=twa&amp;searchHub=BookstoreSearch HTTP/1.1 &nbsp; Accept: application/json Authorization: Bearer **********-****-****-****-************ \n </div> \n </div> </li> \n <li> <p>Requesting query suggestions using the POST method:</p> \n <div class="language-http highlighter-rouge"> \n <div class="highlight">\n POST https://platform.cloud.coveo.com/rest/search/v2/querySuggest HTTP/1.1 &nbsp; Content-Type: application/json Accept: application/json Authorization: Bearer **********-****-****-****-************ \n </div> \n </div> <p>Payload</p> \n <div class="language-json highlighter-rouge"> \n <div class="highlight">\n { "locale": "en", "q": "twa", "searchHub": "BookstoreSearch" } \n </div> \n </div> \n <div class="box success"> \n <p><strong>200 OK response body (excerpt)</strong></p> \n <div class="language-json highlighter-rouge"> \n <div class="highlight">\n { "completions": [ { "executableConfidence": 1, "expression": "mark twain", "highlighted": "[mark] {twa}[in]", "score": 14.525258530973204 }, { "executableConfidence": 0.6666666666666666, "expression": "[wes]{twa}[rd] [ho]", "highlighted": "", "score": 8.50548085208594 }, { "executableConfidence": 0.5, "expression": "hot water music", "highlighted": "[hot] (wat)[er] [music]", "score": 7.107770631785241 }, ... ] } \n </div> \n </div> \n </div> </li> \n </ol> \n</div> <div class="box notes"> \n <ul> \n <li> <p>If the query suggestion request is routed to a <a class="coveo-glossary-entry-link" href="/en/180/">query pipeline</a> with no associated Coveo ML QS model, the request will return an empty completions array.</p> </li> \n <li> <p>In a completions array item:</p> \n <ul> \n <li> <p>The score property value only has relative significance within the same completions array.</p> <p>For instance, a suggestion with a score of 14.811407079917723 in the completions array of response <strong>A</strong> isn’t necessarily less relevant than a suggestion with a score of 24.325728875625282 in the completions array of response <strong>B</strong>.</p> </li> \n <li> <p>The highlighted property uses the following logic:</p> \n <ul> \n <li> <p>Characters between curly braces (e.g., {cat}) indicate an exact match with <a href="#q-string">q</a>.</p> </li> \n <li> <p>Characters between square braces (e.g., [cher]) indicate completions.</p> </li> \n <li> <p>Characters between parentheses (e.g., (act)) indicate corrections to q.</p> </li> \n </ul> </li> \n <li> <p>The executableConfidence property contains a floating-point value between 0 and 1 indicating how "convinced" Coveo ML is that performing a query with this suggestion as a basic query expression will return relevant results. The threshold from which Coveo ML considers a query suggestion executable is 0.8.</p> </li> \n </ul> </li> \n </ul> \n</div>',
documentId: {
contentIdKey: 'permanentid',
contentIdValue: e.results.results[0].raw.permanentid
},
score: 0.99,
relatedQuestions: [
{
question:
'What does Lorem Ipsum mean? What does Lorem Ipsum mean? What does Lorem Ipsum mean? What does Lorem Ipsum mean? What does Lorem Ipsum mean?',
answerSnippet:
"<p>Lorem ipsum is a name for a common type of placeholder text. Also known as filler or dummy text, this is simply copy that serves to fill a space without actually saying anything meaningful. It's essentially nonsense text, but gives an idea of what real text will look like in the final product.</p>",
documentId: { contentIdKey: 'permanentid', contentIdValue: e.results.results[0].raw.permanentid },
score: 0.95
},
{
question: 'What is the use of Lorem Ipsum?',
answerSnippet:
"<p>Lorem ipsum is a pseudo-Latin text used in web design, typography, layout, and printing in place of English to emphasise design elements over content. It's also called placeholder (or filler) text. It's a convenient tool for mock-ups.</p>",
documentId: { contentIdKey: 'permanentid', contentIdValue: e.results.results[0].raw.permanentid },
score: 0.9
},
{
question: 'What does Lorem mean?',
answerSnippet:
'<p>But it wasn\'t long before I realized that Lorem Ipsum is mostly gibberish, a garbling of Latin that makes no real sense. The first word, "Lorem," isn\'t even a word; instead it\'s a piece of the word "dolorem," meaning pain, suffering, or sorrow.</p>',
documentId: { contentIdKey: 'permanentid', contentIdValue: e.results.results[0].raw.permanentid },
score: 0.85
},
{
question: 'Is Lorem Ipsum Latin or Greek?',
answerSnippet:
'<p>"Lorem" isn\'t even a Latin word -- it\'s the second half of "dolorem," meaning "pain" or "sorrow". Thus Lorem Ipsum was born, and began its long journey to ubiquity. The Guardian quoted a Latin scholar on just what the scrambled Cicero "means" to someone who understands Latin.</p>',
documentId: { contentIdKey: 'permanentid', contentIdValue: e.results.results[0].raw.permanentid },
score: 0.8
},
{
question: 'What language is Lorem Ipsum?',
answerSnippet:
'<p><strong>Latin</strong></p> <p>The phrase "Lorem ipsum dolor sit amet consectetuer" appears in Microsoft Word online Help. This phrase has the appearance of an intelligent Latin idiom.</p>',
documentId: { contentIdKey: 'permanentid', contentIdValue: e.results.results[0].raw.permanentid },
score: 0.75
},
{
question: 'Who invented Lorem Ipsum?',
answerSnippet:
'<p><strong>Richard McClintock</strong><p> <p>Richard McClintock, a Latin scholar from Hampden-Sydney College, is credited with discovering the source behind the ubiquitous filler text. In seeing a sample of lorem ipsum, his interest was piqued by consectetur—a genuine, albeit rare, Latin word.</p>',
documentId: { contentIdKey: 'permanentid', contentIdValue: e.results.results[0].raw.permanentid },
score: 0.7
}
]
};
});
}

let smartSnippetSuggestionsElement: Dom;
beforeEach(async done => {
smartSnippetSuggestionsElement = $$('div', { className: Component.computeCssClassName(SmartSnippetSuggestions) });
fakeNextQuestionAnswer();
getResultsColumn().appendChild(smartSnippetSuggestionsElement.el);
await afterDeferredQuerySuccess();
smartSnippetSuggestionsElement.findClass('coveo-smart-snippet-suggestions-question-title-checkbox')[1].click();
done();
});

it('should be accessible', async done => {
const axeResults = await axe.run(smartSnippetSuggestionsElement.el);
expect(axeResults).toBeAccessible();
done();
});
});
};
4 changes: 4 additions & 0 deletions accessibilityTest/Test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ import { AccessibilityQuerySummary } from './AccessibilityQuerySummary';
import { AccessibilityThumbnail } from './AccessibilityThumbnail';
import { AccessibilityCategoryFacet } from './AccessibilityCategoryFacet';
import { AccessibilityDynamicHierarchicalFacetSearch } from './AccessibilityDynamicHierarchicalFacetSearch';
import { AccessibilitySmartSnippet } from './AccessibilitySmartSnippet';
import { AccessibilitySmartSnippetSuggestions } from './AccessibilitySmartSnippetSuggestions';

const getFilename = (path: string) => /\/([^\/]*$)/.exec(path)[1];

Expand Down Expand Up @@ -176,4 +178,6 @@ describe('Testing ...', () => {
AccessibilityThumbnail();
AccessibilityCategoryFacet();
AccessibilityDynamicHierarchicalFacetSearch();
AccessibilitySmartSnippet();
AccessibilitySmartSnippetSuggestions();
});
2 changes: 1 addition & 1 deletion accessibilityTest/Testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export const isInit = () => {
export const waitUntilSelectorIsPresent = <T extends Element = Element>(parentNode: HTMLElement, selector: string) => {
const alreadyExistingElement = parentNode.querySelector<T>(selector);
if (alreadyExistingElement) {
return alreadyExistingElement;
return Promise.resolve(alreadyExistingElement);
}
return observeUntil(
parentNode,
Expand Down
1 change: 1 addition & 0 deletions gulpTasks/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function cleanDefs() {
.pipe(replace(/moment\.[a-zA-Z]+/g, 'any'))
.pipe(replace(/Partial<[A-z]*>/g, 'any'))
.pipe(replace(/<\s?([a-z]+)\s?=\s?[a-z]+\s?>/gi, '<$1>'))
.pipe(replace(/ShadowRootInit/, 'any'))
.pipe(gulp.dest('bin/ts/'))
);
}
Expand Down
1 change: 1 addition & 0 deletions image/svg/check-yes.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions image/svg/clear-small.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit a48171b

Please sign in to comment.