diff --git a/__tests__/groups/group.test.js b/__tests__/groups/group.test.js index b12d8340..70849be4 100644 --- a/__tests__/groups/group.test.js +++ b/__tests__/groups/group.test.js @@ -247,15 +247,6 @@ describe('Discord Groups Page', () => { expect(noResultFoundHeadingText).toEqual('No results found.'); }); - test('should update the URL when a group role is clicked', async () => { - await page.$$eval('.group-role', (elements) => { - elements[1].click(); - }); - const url = await page.url(); - const searchParams = decodeURIComponent(url.split('?')[1]); - expect(searchParams).toMatch('DSA'); - }); - test('should not have group keyword in group list', async () => { const renderedGroupNames = await page.$$eval('.group-name', (elements) => { return elements.map((element) => element.innerText); @@ -300,4 +291,37 @@ describe('Discord Groups Page', () => { ); expect(expectedCreatedByLines).toEqual(createdByLines); }); + + test('should update the URL when input field has changed', async () => { + manageGroup = await page.$('.manage-groups-tab'); + await manageGroup.click(); + const searchInput = await page.$('#search-groups'); + await searchInput.type('DSA'); + await new Promise((resolve) => setTimeout(resolve, 1000)); //wait for debouncer + const url = await page.url(); + const searchParams = decodeURIComponent(url.split('?')[1]); + expect(searchParams).toMatch('DSA'); + }); + + test('should update input field and filter group list with search value in URL', async () => { + await page.goto('http://localhost:8000/groups/?dev=true&DSA'); + manageGroup = await page.$('.manage-groups-tab'); + await manageGroup.click(); + const searchInput = await page.$('#search-groups'); + const inputValue = await page.evaluate( + (element) => element.value, + searchInput, + ); + expect(inputValue).toMatch('DSA'); + + const filteredGroupNames = await page.$$eval('.group-role', (elements) => { + return elements + .map((element) => element.querySelector('.group-name').textContent) + .filter((name) => name.includes('DSA')); + }); + + expect(filteredGroupNames).toEqual( + expect.arrayContaining(['DSA', 'DSA-Coding-Group']), + ); + }); }); diff --git a/__tests__/users/onboarding-31-days-multiple-selections.test.js b/__tests__/users/onboarding-31-days-multiple-selections.test.js new file mode 100644 index 00000000..d06e5d4e --- /dev/null +++ b/__tests__/users/onboarding-31-days-multiple-selections.test.js @@ -0,0 +1,143 @@ +const puppeteer = require('puppeteer'); + +describe('Tests the "Onboarding > 31 Days" Filter', () => { + let browser; + let page; + + jest.setTimeout(60000); + + beforeAll(async () => { + browser = await puppeteer.launch({ + headless: 'new', //change headless to 'new' to check the tests in browser + ignoreHTTPSErrors: true, + args: ['--incognito', '--disable-web-security'], + devtools: false, + }); + page = await browser.newPage(); + + await page.setRequestInterception(true); + + page.on('request', (interceptedRequest) => { + const url = interceptedRequest.url(); + if (url === 'https://api.realdevsquad.com/tasks/sunny-s') { + // When we encounter the respective api call we respond with the below response + interceptedRequest.respond({ + status: 200, + contentType: 'application/json', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + }, + body: JSON.stringify(userDetailsApi), + }); + } else if (url === 'https://api.realdevsquad.com/users/self') { + // When we encounter the respective api call we respond with the below response + interceptedRequest.respond({ + status: 200, + contentType: 'application/json', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + }, + body: JSON.stringify(superUserDetails), // Y contains the json of a superuser in the server which will grant us the access to view the page without locks + }); + } else { + interceptedRequest.continue(); + } + }); + await page.goto('http://localhost:8000/users/?dev=true'); + + await page.waitForNetworkIdle(); + }); + + afterAll(async () => { + await browser.close(); + }); + + it('should gives results for Onboarding > 31 SELECTED', async () => { + const taskDiv = await page.$('.filter-button'); + expect(taskDiv).toBeTruthy(); + + await taskDiv.click(); + + await page.waitForTimeout(2000); + const elements = await page.$$('.checkbox-label'); + + // Checking if elements are found + expect(elements).toBeTruthy(); + + const checkbox = await page.$('#ONBOARDING31DAYS'); + await checkbox.click(); + + const applyfilterbutton = await page.$('.apply-filter-button'); + expect(applyfilterbutton).toBeTruthy(); + await applyfilterbutton.click(); + + await page.waitForTimeout(500); + }); + it('should gives results for ACTIVE SELECTED', async () => { + const taskDiv = await page.$('.filter-button'); + expect(taskDiv).toBeTruthy(); + + await taskDiv.click(); + + // await page.waitForTimeout(2000); enable to see the tests in actions + const elements = await page.$$('.checkbox-label'); + + const clear = await page.$('#clear-button'); + await clear.click(); + + // await page.waitForTimeout(2000); enable to see the tests in actions + + const taskDiv2 = await page.$('.filter-button'); + await taskDiv2.click(); + expect(taskDiv2).toBeTruthy(); + // await page.waitForTimeout(2000); enable to see the tests in actions + expect(elements).toBeTruthy(); + + const checkbox = await page.$('#ACTIVE'); + await checkbox.click(); + + const applyfilterbutton = await page.$('.apply-filter-button'); + expect(applyfilterbutton).toBeTruthy(); + await applyfilterbutton.click(); + + await page.waitForTimeout(500); + }); + + it('should gives results for both ACTIVE & Onboarding > 31 SELECTED', async () => { + const taskDiv = await page.$('.filter-button'); + expect(taskDiv).toBeTruthy(); + + await taskDiv.click(); + + // await page.waitForTimeout(2000); enable to see the tests in actions + const elements = await page.$$('.checkbox-label'); + + // Checking if elements are found + expect(elements).toBeTruthy(); + + const clear = await page.$('#clear-button'); + await clear.click(); + + // await page.waitForTimeout(2000); enable to see the tests in actions + + const taskDiv2 = await page.$('.filter-button'); + await taskDiv2.click(); + expect(taskDiv2).toBeTruthy(); + // await page.waitForTimeout(2000); enable to see the tests in actions + const checkbox = await page.$('#ONBOARDING31DAYS'); + await checkbox.click(); + // await page.waitForTimeout(2000); enable to see the tests in actions + const checkbox2 = await page.$('#ACTIVE'); + await checkbox2.click(); + // await page.waitForTimeout(2000); enable to see the tests in actions + const applyfilterbutton = await page.$('.apply-filter-button'); + expect(applyfilterbutton).toBeTruthy(); + await applyfilterbutton.click(); + + await page.waitForTimeout(500); + }); +}); diff --git a/groups/script.js b/groups/script.js index 3b949cce..2cea9bea 100644 --- a/groups/script.js +++ b/groups/script.js @@ -11,6 +11,7 @@ import { createDiscordGroupRole, getUserSelf, getUserGroupRoles, + getSearchValueFromURL, } from './utils.js'; const groupTabs = document.querySelector('.groups-tab'); const tabs = document.querySelectorAll('.groups-tab div'); @@ -18,8 +19,15 @@ const sections = document.querySelectorAll('.manage-groups, .create-group'); const loader = document.querySelector('.backdrop'); const userIsNotVerifiedText = document.querySelector('.not-verified-tag'); const params = new URLSearchParams(window.location.search); +const searchValue = getSearchValueFromURL(); const isDev = params.get(DEV_FEATURE_FLAG) === 'true'; +// const paragraphElement = null, paragraphContent = ''; +const searchInput = document.getElementById('search-groups'); +//Let searchInput has searchValue as it is independent to API calls mentioned below +if (searchValue) { + searchInput.value = searchValue; +} //User Data const userSelfData = await getUserSelf(); let UserGroupData = await getUserGroupRoles(); @@ -77,8 +85,13 @@ groupsData?.forEach((item) => { item.rolename, ); - if (params.has(formattedRoleName)) { - group.classList.add('active-group'); + //If searchValue present, filter out the list + if (searchValue) { + group.style.display = formattedRoleName + .toUpperCase() + .includes(searchValue.toUpperCase()) + ? '' + : 'none'; } const groupname = document.createElement('p'); @@ -136,15 +149,10 @@ const pathname = window.location.pathname; const groupRolesList = document.querySelectorAll('.group-role'); groupRoles?.addEventListener('click', function (event) { groupRolesList.forEach((groupItem) => { - window.history.pushState({}, '', pathname); groupItem.classList?.remove('active-group'); }); const groupListItem = event.target?.closest('li'); if (groupListItem) { - const devFeatureFlag = isDev ? '&dev=true' : ''; - const rolename = `${groupListItem.querySelector('p').textContent}`; - const newURL = `${window.location.pathname}?${rolename}${devFeatureFlag}`; - window.history.pushState({}, '', newURL); groupListItem.classList.add('active-group'); memberAddRoleBody.roleid = groupListItem.id; if (IsUserVerified) { @@ -175,22 +183,27 @@ function updateButtonState() { : (buttonAddRole.removeEventListener('click', removeRoleHandler), buttonAddRole.addEventListener('click', addrole)); } -// const paragraphElement = null, paragraphContent = ''; -const searchInput = document.getElementById('search-groups'); function debounce(func, delay) { let timeoutId; return function (...args) { - timeoutId = setTimeout(() => { + if (timeoutId) { clearTimeout(timeoutId); + } + timeoutId = setTimeout(() => { func.apply(this, args); }, delay); }; } -searchInput.addEventListener('keyup', () => { - loader.classList.remove('hidden'); +searchInput.addEventListener( + 'input', debounce(() => { + loader.classList.remove('hidden'); + searchInput.disabled = true; //Disable user input when loader is active + const devFeatureFlag = isDev ? '&dev=true' : ''; + const newURL = `${window.location.pathname}?${searchInput.value}${devFeatureFlag}`; + window.history.pushState({}, '', newURL); const searchValue = searchInput.value.toUpperCase(); const groupRoles = document.querySelectorAll('.group-role'); let foundResults = false; @@ -208,8 +221,10 @@ searchInput.addEventListener('keyup', () => { }); const noResultsMessage = document.getElementById('no-results-message'); noResultsMessage.style.display = foundResults ? 'none' : 'block'; - }, 1000)(); -}); + loader.classList.add('hidden'); + searchInput.disabled = false; + }, 500), //Reduced debounce for improved user experience +); /** * TO ASSIGN YOURSELF A ROLE diff --git a/groups/utils.js b/groups/utils.js index 9fb461a0..868d1708 100644 --- a/groups/utils.js +++ b/groups/utils.js @@ -113,6 +113,20 @@ function removeGroupKeywordFromDiscordRoleName(groupName) { return groupName; } +//Function to parse only search value from URL +function getSearchValueFromURL() { + const params = new URLSearchParams(window.location.search); + + let searchValue = null; + + for (const [key, value] of params.entries()) { + if (value === '') { + searchValue = key; + break; + } + } + return searchValue; +} export { getUserGroupRoles, getMembers, @@ -121,4 +135,5 @@ export { createDiscordGroupRole, addGroupRoleToMember, removeGroupKeywordFromDiscordRoleName, + getSearchValueFromURL, }; diff --git a/users/script.js b/users/script.js index 1c7626c8..d10ceabc 100644 --- a/users/script.js +++ b/users/script.js @@ -400,11 +400,10 @@ function populateAvailability() { { name: 'Ooo (Out of Office)', id: 'OOO' }, { name: 'Idle', id: 'IDLE' }, { name: 'Onboarding', id: 'ONBOARDING' }, - { name: 'Onboarding > 31d', id: 'ONBOARDING31DAYS' }, ]; - if (params.get('dev') != 'true') { - availabilityArr.pop(); + if (params.get('dev') === 'true') { + availabilityArr.push({ name: 'Onboarding > 31d', id: 'ONBOARDING31DAYS' }); } for (let i = 0; i < availabilityArr.length; i++) { const { name, id } = availabilityArr[i]; @@ -585,18 +584,6 @@ async function persistUserDataBasedOnQueryParams() { } } -async function getUsersInOnboardingFor31Days() { - try { - const usersRequest = await makeApiCall( - `${RDS_API_USERS}/search/?state=ONBOARDING&time=31d`, - ); - const { users } = await usersRequest.json(); - return users; - } catch (err) { - throw new Error(`User list request failed with error: ${err}`); - } -} - // Function to apply the filter when the "Apply Filter" button is clicked applyFilterButton.addEventListener('click', async () => { filterModal.classList.toggle('hidden'); @@ -608,17 +595,49 @@ applyFilterButton.addEventListener('click', async () => { checkedValuesSkills, checkedValuesAvailability, ); - // Check if the "Onboarding > 31 Days" checkbox is checked - const onboarding31DaysFilter = - document.getElementById('ONBOARDING31DAYS').checked; - try { - let users; - if (onboarding31DaysFilter) { - // If the checkbox is checked, fetch users from the specific API endpoint - users = await getUsersInOnboardingFor31Days(); - } else { - // If the checkbox is not checked, fetch users with other filters + // Feature Flag Start + if (params.get('dev') === 'true') { + const onboarding31DaysFilter = + document.getElementById('ONBOARDING31DAYS').checked; + try { + let users; + if (onboarding31DaysFilter) { + let queryParams = getFilteredUsersURL( + checkedValuesSkills, + checkedValuesAvailability, + ); + + queryParams = replaceOnboarding31days(queryParams); + const usersRequest = await makeApiCall( + `${RDS_API_USERS}/search${queryParams}`, + ); + const { users: filteredUsers } = await usersRequest.json(); + users = filteredUsers; + } else { + let queryParams = getFilteredUsersURL( + checkedValuesSkills, + checkedValuesAvailability, + ); + const usersRequest = await makeApiCall( + `${RDS_API_USERS}/search${queryParams}`, + ); + const { users: filteredUsers } = await usersRequest.json(); + users = filteredUsers; + } + + manipulateQueryParamsToURL(queryParams); + // Display the filtered user list + showUserList(users); + } catch (err) { + throw new Error(`User list request failed with error: ${err}`); + } + } + // feature flag end + else { + try { + let users; + const queryParams = getFilteredUsersURL( checkedValuesSkills, checkedValuesAvailability, @@ -628,16 +647,35 @@ applyFilterButton.addEventListener('click', async () => { ); const { users: filteredUsers } = await usersRequest.json(); users = filteredUsers; - } - manipulateQueryParamsToURL(queryParams); - // Display the filtered user list - showUserList(users); - } catch (err) { - throw new Error(`User list request failed with error: ${err}`); + manipulateQueryParamsToURL(queryParams); + // Display the filtered user list + showUserList(users); + } catch (err) { + throw new Error(`User list request failed with error: ${err}`); + } } }); +function replaceOnboarding31days(queryParams) { + if (queryParams.includes('&state=ONBOARDING31DAYS')) { + // Replace "&state=ONBOARDING31DAYS" with "&state=ONBOARDING&time=31d" + queryParams = queryParams.replace( + '&state=ONBOARDING31DAYS', + '&state=ONBOARDING&time=31d', + ); + return queryParams; + } + if (queryParams.includes('?state=ONBOARDING31DAYS')) { + // Replace "&state=ONBOARDING31DAYS" with "&state=ONBOARDING&time=31d" + queryParams = queryParams.replace( + '?state=ONBOARDING31DAYS', + '?state=ONBOARDING&time=31d', + ); + return queryParams; + } +} + function clearCheckboxes(name) { const checkboxes = document.querySelectorAll(`input[name="${name}"]`); checkboxes.forEach((cb) => {