From 1c885077848658403b84f3b0b3ea47763b4a1869 Mon Sep 17 00:00:00 2001 From: Onokaev Date: Fri, 3 Mar 2023 13:16:35 +0300 Subject: [PATCH 1/5] Fix autocomplete filter --- .../auto-complete/AutoComplete.tsx | 3 +++ .../suggestions/utilities/delimiters.ts | 16 +------------- .../ui/anonymous-experiences/request.spec.ts | 21 +++++++++++++++---- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx b/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx index 9e8cd4eace..ddb4e49ad8 100644 --- a/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx +++ b/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx @@ -220,6 +220,9 @@ const AutoComplete = (props: IAutoCompleteProps) => { let query = selected; if (selected.startsWith(delimiters.DOLLAR.symbol)) { + if(queryUrl.includes(delimiters.DOLLAR.symbol)){ + selected = selected.substring(1, selected.length); + } selected += delimiters.EQUALS.symbol; query = ''; } diff --git a/src/modules/suggestions/utilities/delimiters.ts b/src/modules/suggestions/utilities/delimiters.ts index c2f1738821..66544e1fb2 100644 --- a/src/modules/suggestions/utilities/delimiters.ts +++ b/src/modules/suggestions/utilities/delimiters.ts @@ -27,24 +27,10 @@ const delimiters: Delimiters = { function getLastDelimiterInUrl(url: string): Delimiter { const symbols = Object.values(delimiters); symbols.forEach(key => { - const prevCharIndex = url.lastIndexOf(key.symbol) - 1; - key.index = isSecondLastCharADelimiter(url.charAt(prevCharIndex)) ? url.lastIndexOf(key.symbol)-1 : - url.lastIndexOf(key.symbol); + key.index = url.lastIndexOf(key.symbol); }); return symbols.reduce((prev, current) => (prev.index > current.index) ? prev : current); } -const isSecondLastCharADelimiter = (prevCharacter: string): boolean => { - const symbols = Object.values(delimiters); - let isSecondLastCharDelimiter = false; - for(const symbol of symbols ){ - if(prevCharacter === symbol.symbol){ - isSecondLastCharDelimiter = true; - break; - } - } - return isSecondLastCharDelimiter; -} - export { delimiters, getLastDelimiterInUrl } \ No newline at end of file diff --git a/src/tests/ui/anonymous-experiences/request.spec.ts b/src/tests/ui/anonymous-experiences/request.spec.ts index 71c3cd5329..409296b96b 100644 --- a/src/tests/ui/anonymous-experiences/request.spec.ts +++ b/src/tests/ui/anonymous-experiences/request.spec.ts @@ -75,7 +75,7 @@ test.describe('Run query', () => { await page.locator('label:has-text("messages")').click(); await page.evaluate(() => document.fonts.ready); expect(await page.screenshot({ clip: { x: 300, y: 0, width: 1920, height: 1080 } })).toMatchSnapshot(); - await queryInputField.type('?sel'); + await queryInputField.type('?$sel'); await page.locator('label:has-text("$select")').click(); await page.evaluate(() => document.fonts.ready); expect(await page.screenshot({ clip: { x: 300, y: 0, width: 1920, height: 1080 } })).toMatchSnapshot(); @@ -83,11 +83,24 @@ test.describe('Run query', () => { await queryInputField.press('Tab'); await page.evaluate(() => document.fonts.ready); expect(await page.screenshot({ clip: { x: 300, y: 0, width: 1920, height: 1080 } })).toMatchSnapshot(); - // eslint-disable-next-line max-len - expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/v1.0/me/messages?$select=id")').toBeDefined() + expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/v1.0/me/messages?$select=id,changeKey")').toBeDefined() }); + test('Tests query parameter addition on autocomplete', async () => { + const queryInputField = page.locator('[aria-label="Query sample input"]'); + await queryInputField.click(); + await page.evaluate(() => document.fonts.ready); + await queryInputField.fill(''); + await queryInputField.fill('https://graph.microsoft.com/v1.0/me/messages'); + await queryInputField.type('?sel'); + await page.locator('label:has-text("$select")').click(); + await page.evaluate(() => document.fonts.ready); + await queryInputField.press('Tab'); + await queryInputField.press('Tab'); + expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/v1.0/me/messages?$select=id")').toBeDefined() + }) + test('user can run query', async () => { const profileSample = page.locator('[aria-label="my profile"]'); await profileSample.click(); @@ -134,7 +147,7 @@ test.describe('Run query', () => { }); -test.describe.serial('Request section', () => { +test.describe.serial('Request section', () => { //was serial before skip test('should add request headers', async () => { const queryInput = page.locator('[aria-label="Query sample input"]'); await queryInput.click(); From 297e8b8b34a6dc22b242379acf858d54cb90b972 Mon Sep 17 00:00:00 2001 From: Onokaev Date: Mon, 6 Mar 2023 16:28:24 +0300 Subject: [PATCH 2/5] Pass query URL for Enter event --- src/app/views/query-runner/QueryRunner.tsx | 8 +++++++- src/app/views/query-runner/query-input/QueryInput.tsx | 8 ++++++-- .../query-input/auto-complete/AutoComplete.tsx | 6 +----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/app/views/query-runner/QueryRunner.tsx b/src/app/views/query-runner/QueryRunner.tsx index aa7662f52c..98a520546c 100644 --- a/src/app/views/query-runner/QueryRunner.tsx +++ b/src/app/views/query-runner/QueryRunner.tsx @@ -6,6 +6,7 @@ import { useDispatch } from 'react-redux'; import { AppDispatch, useAppSelector } from '../../../store'; import { componentNames, eventTypes, telemetry } from '../../../telemetry'; import { ContentType } from '../../../types/enums'; +import { IQuery } from '../../../types/query-runner'; import { runQuery } from '../../services/actions/query-action-creators'; import { setSampleQuery } from '../../services/actions/query-input-action-creators'; import { setQueryResponseStatus } from '../../services/actions/query-status-action-creator'; @@ -37,7 +38,7 @@ const QueryRunner = (props: any) => { setSampleBody(value!); }; - const handleOnRunQuery = () => { + const handleOnRunQuery = (query?: IQuery) => { if (sampleBody) { const headers = sampleQuery.sampleHeaders; const contentType = headers.find(k => k.name.toLowerCase() === 'content-type'); @@ -58,6 +59,11 @@ const QueryRunner = (props: any) => { sampleQuery.sampleBody = sampleBody; } } + if(query) { + sampleQuery.sampleUrl = query.sampleUrl; + sampleQuery.selectedVersion = query.selectedVersion; + sampleQuery.selectedVerb = query.selectedVerb; + } dispatch(runQuery(sampleQuery)); const sanitizedUrl = sanitizeQueryUrl(sampleQuery.sampleUrl); diff --git a/src/app/views/query-runner/query-input/QueryInput.tsx b/src/app/views/query-runner/query-input/QueryInput.tsx index 2a46fe8619..2ce083ec85 100644 --- a/src/app/views/query-runner/query-input/QueryInput.tsx +++ b/src/app/views/query-runner/query-input/QueryInput.tsx @@ -60,11 +60,15 @@ const QueryInput = (props: IQueryInputProps) => { return query; } - const runQuery = () => { + const runQuery = (queryUrl?: string) => { if (!sampleQuery.sampleUrl || sampleQuery.sampleUrl.indexOf('graph.microsoft.com') === -1) { return; } - handleOnRunQuery(sampleQuery); + let query: IQuery = sampleQuery; + if (queryUrl) { + query = getChangedQueryContent(queryUrl); + } + handleOnRunQuery(query); }; const queryInputStackTokens: IStackTokens = { diff --git a/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx b/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx index ddb4e49ad8..ccdf4aaafb 100644 --- a/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx +++ b/src/app/views/query-runner/query-input/auto-complete/AutoComplete.tsx @@ -105,7 +105,7 @@ const AutoComplete = (props: IAutoCompleteProps) => { appendSuggestionToUrl(selected); } else { props.contentChanged(queryUrl); - props.runQuery(); + props.runQuery(queryUrl); } break; @@ -200,10 +200,6 @@ const AutoComplete = (props: IAutoCompleteProps) => { if (filtered.length === 1 && filtered[0] === searchTerm) { appendSuggestionToUrl(searchTerm); } - - if(filtered.length === 0){ - props.contentChanged(queryUrl); - } } const trackSuggestionSelectionEvent = (suggestion: string) => { From 866f89580f08a2ce934ea5b5e85b86646b968524 Mon Sep 17 00:00:00 2001 From: Onokaev Date: Tue, 7 Mar 2023 08:37:58 +0300 Subject: [PATCH 3/5] Refactor getLastDelimiter method --- .../suggestions/utilities/delimiters.ts | 16 ++++++---- .../ui/anonymous-experiences/request.spec.ts | 32 +++++++++++++++++-- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/modules/suggestions/utilities/delimiters.ts b/src/modules/suggestions/utilities/delimiters.ts index 66544e1fb2..ab3dd1231c 100644 --- a/src/modules/suggestions/utilities/delimiters.ts +++ b/src/modules/suggestions/utilities/delimiters.ts @@ -25,12 +25,16 @@ const delimiters: Delimiters = { }; function getLastDelimiterInUrl(url: string): Delimiter { - const symbols = Object.values(delimiters); - symbols.forEach(key => { - key.index = url.lastIndexOf(key.symbol); - }); - - return symbols.reduce((prev, current) => (prev.index > current.index) ? prev : current); + const symbols: Delimiter[] = Object.values(delimiters); + for (let i = url.length - 1; i >= 0; i--) { + const symbol = symbols.find((s) => s.symbol === url[i]); + if (symbol) { + symbol.index = i; + return symbol; + } + } + return delimiters.SLASH; } + export { delimiters, getLastDelimiterInUrl } \ No newline at end of file diff --git a/src/tests/ui/anonymous-experiences/request.spec.ts b/src/tests/ui/anonymous-experiences/request.spec.ts index 409296b96b..c14744c26d 100644 --- a/src/tests/ui/anonymous-experiences/request.spec.ts +++ b/src/tests/ui/anonymous-experiences/request.spec.ts @@ -84,7 +84,7 @@ test.describe('Run query', () => { await page.evaluate(() => document.fonts.ready); expect(await page.screenshot({ clip: { x: 300, y: 0, width: 1920, height: 1080 } })).toMatchSnapshot(); // eslint-disable-next-line max-len - expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/v1.0/me/messages?$select=id,changeKey")').toBeDefined() + expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/v1.0/me/messages?$select=id")').toBeDefined() }); test('Tests query parameter addition on autocomplete', async () => { @@ -101,6 +101,34 @@ test.describe('Run query', () => { expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/v1.0/me/messages?$select=id")').toBeDefined() }) + test('Tests $filter query parameter for v1 version', async () => { + const queryInputField = page.locator('[aria-label="Query sample input"]'); + await queryInputField.click(); + await page.evaluate(() => document.fonts.ready); + await queryInputField.fill(''); + await queryInputField.fill('https://graph.microsoft.com/v1.0/users'); + await queryInputField.type('?fil'); + await page.locator('label:has-text("$filter")').click(); + await page.evaluate(() => document.fonts.ready); + await queryInputField.press('Tab'); + await queryInputField.press('Tab'); + await queryInputField.type('startsWith(displayName, \'Megan\')'); + expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/v1.0/users?$filter=startsWith(displayName, \'Megan\')")').toBeDefined(); + }) + + test('Tests query parameter for beta version that do not require a $ sign', async () => { + const queryInputField = page.locator('[aria-label="Query sample input"]'); + await queryInputField.click(); + await page.evaluate(() => document.fonts.ready); + await queryInputField.fill(''); + await queryInputField.fill('https://graph.microsoft.com/beta/me/messages'); + await queryInputField.type('?select=id,sender'); + const runQueryButton = page.locator('.run-query-button button'); + await runQueryButton.click(); + expect('input[aria-label="Query sample input"]:has-text("https://graph.microsoft.com/beta/me/messages?select=id,sender")').toBeDefined(); + expect(page.getByText('"Microsoft Viva"')).toBeDefined(); + }) + test('user can run query', async () => { const profileSample = page.locator('[aria-label="my profile"]'); await profileSample.click(); @@ -147,7 +175,7 @@ test.describe('Run query', () => { }); -test.describe.serial('Request section', () => { //was serial before skip +test.describe.serial('Request section', () => { test('should add request headers', async () => { const queryInput = page.locator('[aria-label="Query sample input"]'); await queryInput.click(); From fb331daa25d536b18ec7984cb011f04319d018a5 Mon Sep 17 00:00:00 2001 From: Onokaev Date: Tue, 7 Mar 2023 10:10:41 +0300 Subject: [PATCH 4/5] Validate query after operations --- src/app/views/query-runner/query-input/QueryInput.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/views/query-runner/query-input/QueryInput.tsx b/src/app/views/query-runner/query-input/QueryInput.tsx index 2ce083ec85..58e1fb8db3 100644 --- a/src/app/views/query-runner/query-input/QueryInput.tsx +++ b/src/app/views/query-runner/query-input/QueryInput.tsx @@ -61,13 +61,13 @@ const QueryInput = (props: IQueryInputProps) => { } const runQuery = (queryUrl?: string) => { - if (!sampleQuery.sampleUrl || sampleQuery.sampleUrl.indexOf('graph.microsoft.com') === -1) { - return; - } let query: IQuery = sampleQuery; if (queryUrl) { query = getChangedQueryContent(queryUrl); } + if (!query.sampleUrl || query.sampleUrl.indexOf('graph.microsoft.com') === -1) { + return; + } handleOnRunQuery(query); }; From 590526e9d6f27299860c1e0901737de76d468c7b Mon Sep 17 00:00:00 2001 From: Onokaev Date: Tue, 7 Mar 2023 12:09:25 +0300 Subject: [PATCH 5/5] Add test for Enter key query runs --- .../ui/anonymous-experiences/request.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tests/ui/anonymous-experiences/request.spec.ts b/src/tests/ui/anonymous-experiences/request.spec.ts index c14744c26d..5688935366 100644 --- a/src/tests/ui/anonymous-experiences/request.spec.ts +++ b/src/tests/ui/anonymous-experiences/request.spec.ts @@ -144,6 +144,24 @@ test.describe('Run query', () => { expect(messageBar).toBeDefined(); }); + test('User can run query using the Enter key and different results are received for different queries', async () => { + const queryInputField = page.locator('[aria-label="Query sample input"]'); + await queryInputField.click(); + await page.evaluate(() => document.fonts.ready); + await queryInputField.fill(''); + await queryInputField.fill('https://graph.microsoft.com/v1.0/me'); + await queryInputField.press('Enter'); + await page.waitForTimeout(100); + await page.evaluate(() => document.fonts.ready); + expect(page.getByText('"Megan Bowen"')).toBeDefined(); + await queryInputField.fill(''); + await queryInputField.fill('https://graph.microsoft.com/v1.0/me/messages?$select=sender'); + await queryInputField.press('Enter'); + await page.waitForTimeout(100); + await page.evaluate(() => document.fonts.ready); + expect(page.getByText('"Microsoft Viva"')).toBeDefined(); + }) + test('should show documentation link for queries with links ', async () => { await page.locator('[aria-label="my profile"]').click(); await page.locator('[aria-label="More Info"]').click();