diff --git a/.circleci/config.yml b/.circleci/config.yml index bf7374129..fb3293fd1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -188,7 +188,7 @@ workflows: - build-dev filters: &filters-dev branches: - only: ['dev', 'feature/copilot-feedback'] + only: ['dev', 'feature/new-milestone-concept'] - deployTest01: context : org-global diff --git a/connect-automation/config/config.json b/connect-automation/config/config.json index 06dd18781..903c05ba8 100644 --- a/connect-automation/config/config.json +++ b/connect-automation/config/config.json @@ -24,5 +24,6 @@ "notificationsUrl": "https://connect.topcoder-dev.com/notifications", "allProjectsUrl": "https://connect.topcoder-dev.com/projects", "givenProjectUrl": "https://connect.topcoder-dev.com/projects/18013", - "expiredProjectUrl": "https://connect.topcoder-dev.com/projects/17236" + "expiredProjectUrl": "https://connect.topcoder-dev.com/projects/17236", + "platformUrl": "https://platform.topcoder-dev.com/taas/myteams" } diff --git a/connect-automation/page-objects/common-page/common.helper.ts b/connect-automation/page-objects/common-page/common.helper.ts index b33938637..09842d546 100644 --- a/connect-automation/page-objects/common-page/common.helper.ts +++ b/connect-automation/page-objects/common-page/common.helper.ts @@ -367,4 +367,11 @@ export const CommonHelper = { } return isElementPresent; }, + + /** + * Get Join Project Button + */ + get joinProjectButton() { + return ElementHelper.getElementByButtonText('Join project'); + }, }; diff --git a/connect-automation/page-objects/phase-creation-flow/create-new-phase/create-new-phase.helper.ts b/connect-automation/page-objects/phase-creation-flow/create-new-phase/create-new-phase.helper.ts index 9bde263fb..29717ffd2 100644 --- a/connect-automation/page-objects/phase-creation-flow/create-new-phase/create-new-phase.helper.ts +++ b/connect-automation/page-objects/phase-creation-flow/create-new-phase/create-new-phase.helper.ts @@ -19,6 +19,12 @@ export class CreateNewPhaseHelper { * @param formData phase creation form data defined in test data */ public static async verifyCreateNewPhase(formData: IPhaseCreationData) { + // If user is invited to project, click on "Join Project" to proceed. + await BrowserHelper.sleep(4000); + if (await CommonHelper.joinProjectButton.isPresent()) { + await CommonHelper.joinProjectButton.click(); + } + await this.clickOnAddNewPhaseButton(); await this.fillCreatePhaseForm(formData.title, formData.daysBetweenStartAndEndDate); diff --git a/connect-automation/page-objects/project-creation-flow/create-project/create-project.helper.ts b/connect-automation/page-objects/project-creation-flow/create-project/create-project.helper.ts index 3d0661baa..6b073c476 100644 --- a/connect-automation/page-objects/project-creation-flow/create-project/create-project.helper.ts +++ b/connect-automation/page-objects/project-creation-flow/create-project/create-project.helper.ts @@ -1,6 +1,7 @@ import { BrowserHelper } from 'topcoder-testing-lib'; +import { ConfigHelper } from '../../../utils/config-helper'; import { CommonHelper } from '../../common-page/common.helper'; -import { IAnswers, IProjectData } from './create-project.model'; +import { IAnswers, IProjectData, ITaasData } from './create-project.model'; import { CreateProjectPageObject } from './create-project.po'; export class CreateProjectPageHelper { @@ -29,8 +30,8 @@ export class CreateProjectPageHelper { await this.clickNewProjectButton(); await this.navigateToViewSolutions(); - await this.clickOnDesignDevelopmentDeploymentButton(); - await this.fillBeforeWeStartForm(projectData.answers); + await this.clickOnSelectButton(); + await this.fillBeforeWeStartForm(projectData.answers, 'Basic Details'); await this.fillBasicDetailsForm( appNameWithDate, projectData.appDescription @@ -40,6 +41,29 @@ export class CreateProjectPageHelper { await this.goToYourProject(appNameWithDate); } + /** + * verify whether the current user can create a TAAS project + */ + public static async verifyTaasProject(taasData: ITaasData) { + await this.clickNewProjectButton(); + await this.navigateToTopTalent(); + await this.clickOnSelectButton(); + await this.fillBeforeWeStartForm(taasData.answers, 'Talent as a Service: Getting Started'); + await this.fillTaasProjectTitleForm(taasData.title); + await this.verifyAddJobItem(); + await this.verifyDeleteJobItem(); + await this.fillJobForm(taasData); + await this.fillTalentRequirementForm(taasData.answers, 'Your Talent Requirements'); + await this.fillRequirementForm(taasData.answers, taasData.email); + + await this.createProjectPageObject.submitJobRequest.click(); + await CommonHelper.verifySuccessAlert(`PROJECT '${taasData.title.toUpperCase()}' CREATED`); + + await this.createProjectPageObject.viewTalentRequestButton.click(); + await BrowserHelper.sleep(10000); + await CommonHelper.verifyPageUrl(ConfigHelper.getPlatformUrl()); + } + private static createProjectPageObject: CreateProjectPageObject; /** @@ -100,10 +124,19 @@ export class CreateProjectPageHelper { expect(title).toBe('TOPCODER SOLUTIONS'); } + /** + * Click on "Tap Into Top Talen" under "TAAS" section + */ + private static async navigateToTopTalent() { + await this.createProjectPageObject.tapIntoTopTalent.click(); + const title = await this.createProjectPageObject.solutionCatalogTitle.getText(); + expect(title).toBe('ENGAGE TALENT'); + } + /** * Click on "Select" button under Design, Development and Deployment. */ - private static async clickOnDesignDevelopmentDeploymentButton() { + private static async clickOnSelectButton() { const selectButton = await this.createProjectPageObject.selectButton(); await selectButton.click(); await this.verifyFormDisplayed('Before we start'); @@ -112,14 +145,29 @@ export class CreateProjectPageHelper { /** * Fill Before We Start form * @param answers answers object defined by test data + * @param formTitle form title to be expected */ - private static async fillBeforeWeStartForm(answers: IAnswers) { + private static async fillBeforeWeStartForm(answers: IAnswers, formTitle: string) { const { beforeWeStart } = answers; await CommonHelper.selectInputByContainingText(beforeWeStart); await this.createProjectPageObject.nextButton.click(); - await this.verifyFormDisplayed('Basic Details'); + await this.verifyFormDisplayed(formTitle); + } + + /** + * Fill Before We Start form + * @param answers answers object defined by test data + * @param formTitle form title to be expected + */ + private static async fillTalentRequirementForm(answers: IAnswers, formTitle: string) { + const { startDate } = answers; + await CommonHelper.selectInputByContainingText(startDate); + + await this.createProjectPageObject.nextButton.click(); + + await this.verifyFormDisplayed(formTitle); } /** @@ -138,6 +186,69 @@ export class CreateProjectPageHelper { await this.verifyFormDisplayed('App Definition'); } + /** + * Fill Taas Project title, then click next + * @param title taas application title + */ + private static async fillTaasProjectTitleForm(title: string) { + const name = this.createProjectPageObject.appNameInput; + await CommonHelper.fillInputField(name, title); + await this.createProjectPageObject.nextButton.click(); + + await this.verifyFormDisplayed('Your Talent Requirements'); + } + + /** + * Fill Requirement Form, then click next + * @param title taas application title + * @param email + */ + private static async fillRequirementForm(answers: IAnswers, email: string) { + const { requirement } = answers; + await CommonHelper.selectInputByContainingText(requirement); + + await this.createProjectPageObject.emailInput.click(); + await this.createProjectPageObject.emailInput.sendKeys(email); + + await this.createProjectPageObject.nextButton.click(); + } + + /** + * Fill Taas Job Form + * @param taasData + */ + private static async fillJobForm(taasData: ITaasData) { + const { jobTitle, numOfPeople, duration, description } = taasData; + + const titleEl = this.createProjectPageObject.titleInput; + await CommonHelper.fillInputField(titleEl, jobTitle); + + const numberInputs = await this.createProjectPageObject.numberInputEls(); + await CommonHelper.fillInputField(numberInputs[0], numOfPeople + ''); + await CommonHelper.fillInputField(numberInputs[1], duration + ''); + + const dropdownInputs = await this.createProjectPageObject.dropdownEls(); + await dropdownInputs[0].click(); + let dropdownOptions = await this.createProjectPageObject.dropdownOptions(); + await dropdownOptions[1].click(); + + await dropdownInputs[1].click(); + dropdownOptions = await this.createProjectPageObject.dropdownOptions(); + await BrowserHelper.sleep(200); + await dropdownOptions[6].click(); + + await this.createProjectPageObject.editorTextarea.click(); + await this.createProjectPageObject.editorTextareaInput.sendKeys(description); + + await this.createProjectPageObject.skillsInput.click(); + await BrowserHelper.sleep(2500); + await this.createProjectPageObject.multiSelectOption.click(); + + await this.createProjectPageObject.nextButton.click(); + + await this.verifyFormDisplayed('Your Talent Requirements'); + } + /** * Fill App Definition Form, then click next * @param projectData project data from test data @@ -191,4 +302,22 @@ export class CreateProjectPageHelper { expect(await CommonHelper.projectTitle().getText()).toBe(appName); } + + /** + * Add job item and verify Add Job Item + */ + private static async verifyAddJobItem() { + await this.createProjectPageObject.plusIcon.click(); + let jobFormNumber = await this.createProjectPageObject.taasJobForm(); + expect(jobFormNumber.length).toBe(2); + } + + /** + * Delete job item and verify Deletion of Job Item + */ + private static async verifyDeleteJobItem() { + await this.createProjectPageObject.deleteIcon.click(); + const jobFormNumber = await this.createProjectPageObject.taasJobForm(); + expect(jobFormNumber.length).toBe(1); + } } diff --git a/connect-automation/page-objects/project-creation-flow/create-project/create-project.model.ts b/connect-automation/page-objects/project-creation-flow/create-project/create-project.model.ts index 3b548153d..61795672d 100644 --- a/connect-automation/page-objects/project-creation-flow/create-project/create-project.model.ts +++ b/connect-automation/page-objects/project-creation-flow/create-project/create-project.model.ts @@ -5,11 +5,23 @@ export interface IProjectData { notes: string; } +export interface ITaasData { + title: string; + jobTitle: string; + numOfPeople: number; + duration: number; + description: string; + email: string; + answers: IAnswers; +} + export interface IAnswers { beforeWeStart: string; - whatDoYouNeed: string; - willYourAppNeedMoreScreen: string; - howManyScreens: string; - whereShouldAppWork: string; - howShouldAppWorks: string; + whatDoYouNeed?: string; + willYourAppNeedMoreScreen?: string; + howManyScreens?: string; + whereShouldAppWork?: string; + howShouldAppWorks?: string; + startDate?: string; + requirement?: string; } diff --git a/connect-automation/page-objects/project-creation-flow/create-project/create-project.po.ts b/connect-automation/page-objects/project-creation-flow/create-project/create-project.po.ts index d434a4281..3594e252a 100644 --- a/connect-automation/page-objects/project-creation-flow/create-project/create-project.po.ts +++ b/connect-automation/page-objects/project-creation-flow/create-project/create-project.po.ts @@ -33,6 +33,13 @@ export class CreateProjectPageObject { return ElementHelper.getElementByButtonText('View Solutions'); } + /** + * Get Tap Into Top Talent button from Create Project Page + */ + public get tapIntoTopTalent() { + return ElementHelper.getElementByButtonText('Tap Into Top Talent'); + } + /** * Get Solution Catalog Page's title element */ @@ -74,6 +81,20 @@ export class CreateProjectPageObject { return ElementHelper.getElementByButtonText('Save my project'); } + /** + * Get Submit Job Request button + */ + public get submitJobRequest() { + return ElementHelper.getElementByButtonText('Submit job request'); + } + + /** + * Get view Talent Request button + */ + public get viewTalentRequestButton() { + return ElementHelper.getElementByCss('.go-to-project-dashboard-btn'); + } + /** * Get Current Form Page's title element */ @@ -104,6 +125,20 @@ export class CreateProjectPageObject { return ElementHelper.getElementByName('description'); } + /** + * Get job title element + */ + public get titleInput() { + return ElementHelper.getElementByName('title'); + } + + /** + * Get email input element + */ + public get emailInput() { + return ElementHelper.getElementByName('details.taasDefinition.hiringManager'); + } + /** * Get Draft Project title */ @@ -125,6 +160,27 @@ export class CreateProjectPageObject { return ElementHelper.getElementByName('details.apiDefinition.notes'); } + /** + * Get plus icon + */ + public get plusIcon() { + return ElementHelper.getElementByClassName('ZALPRV'); + } + + /** + * Get delete icon + */ + public get deleteIcon() { + return ElementHelper.getElementByCss('.ZALPRV._1SfKng'); + } + + /** + * Get taas job form + */ + public async taasJobForm() { + return ElementHelper.getAllElementsByClassName('_3mAtc-'); + } + /** * Get sub title */ @@ -134,6 +190,58 @@ export class CreateProjectPageObject { ); } + /** + * Get number input elements + */ + public async numberInputEls() { + const els = await ElementHelper.getAllElementsByCss('.tc-file-field__inputs.trlMaU'); + return els; + } + + /** + * Get dropdown elements + */ + public async dropdownEls() { + const els = await ElementHelper.getAllElementsByCss('.dropdown-wrap.SelectDropdown.default'); + return els; + } + + /** + * Get dropdown options + */ + public async dropdownOptions() { + const els = await ElementHelper.getAllElementsByClassName('dropdown-menu-list-item'); + return els; + } + + /** + * Get editor textarea + */ + public get editorTextarea() { + return ElementHelper.getElementByClassName('te-editor-section'); + } + + /** + * Get editor textarea input + */ + public get editorTextareaInput() { + return ElementHelper.getElementByCss('.tui-editor-contents.tui-editor-contents-placeholder'); + } + + /** + * Get skills input + */ + public get skillsInput() { + return ElementHelper.getElementByCss('.css-1hwfws3.react-select__value-container.react-select__value-container--is-multi'); + } + + /** + * Get multi select option + */ + public get multiSelectOption() { + return ElementHelper.getElementByCss('.css-fk865s-option.react-select__option'); + } + /** * Wait for subtitle to show */ diff --git a/connect-automation/page-objects/project-creation-flow/projects/projects.helper.ts b/connect-automation/page-objects/project-creation-flow/projects/projects.helper.ts index 8fa8b8e62..417fbddb5 100644 --- a/connect-automation/page-objects/project-creation-flow/projects/projects.helper.ts +++ b/connect-automation/page-objects/project-creation-flow/projects/projects.helper.ts @@ -30,7 +30,7 @@ export class ProjectsHelper { await BrowserHelper.sleep(4000); // Click on Join Project button - await this.projectsPageObject.joinProjectButton.click(); + await CommonHelper.joinProjectButton.click(); const alertElement = CommonHelper.alertBox(); await CommonHelper.waitForSuccessAlert(alertElement); diff --git a/connect-automation/page-objects/project-creation-flow/projects/projects.po.ts b/connect-automation/page-objects/project-creation-flow/projects/projects.po.ts index 704fc65a8..442e4e4f4 100644 --- a/connect-automation/page-objects/project-creation-flow/projects/projects.po.ts +++ b/connect-automation/page-objects/project-creation-flow/projects/projects.po.ts @@ -12,13 +12,6 @@ export class ProjectsPageObject { logger.info('User navigated to Home Page'); } - /** - * Get Join Project Button - */ - public get joinProjectButton() { - return ElementHelper.getElementByButtonText('Join project'); - } - /** * Get Search Input */ diff --git a/connect-automation/smoketest.sh b/connect-automation/smoketest.sh index 2a9c56fb8..27ebc24ec 100755 --- a/connect-automation/smoketest.sh +++ b/connect-automation/smoketest.sh @@ -3,4 +3,5 @@ cd connect-automation docker build -t conn-smoke:latest . -docker run --shm-size=2g conn-smoke:latest ./testrun.sh -d -p 4444:4444 +docker run --name conn-smoke --shm-size=2g conn-smoke:latest ./testrun.sh -d -p 4444:4444 +docker cp conn-smoke:./connect-automation/test-results . \ No newline at end of file diff --git a/connect-automation/test-data/test-data.json b/connect-automation/test-data/test-data.json index e76380548..9f12d5299 100644 --- a/connect-automation/test-data/test-data.json +++ b/connect-automation/test-data/test-data.json @@ -26,6 +26,19 @@ }, "notes": "Notes from test" }, + "taas": { + "title": "test Taas Project", + "jobTitle": "Test Job Title", + "email": "mailmemakar@gmail.com", + "numOfPeople": 4, + "duration": 10, + "description": "test description", + "answers": { + "beforeWeStart": "I need work done", + "startDate": "As soon as possible", + "requirement": "No additional onboarding processes are required" + } + }, "inviteCopilot": { "copilotHandle": "TCConnCopilot" }, diff --git a/connect-automation/test-suites/project-creation-flow/create-project.spec.ts b/connect-automation/test-suites/project-creation-flow/create-project.spec.ts index ae7228879..0c0a284d4 100644 --- a/connect-automation/test-suites/project-creation-flow/create-project.spec.ts +++ b/connect-automation/test-suites/project-creation-flow/create-project.spec.ts @@ -26,6 +26,10 @@ describe('Connect App - Create Project Tests:', () => { await CreateProjectPageHelper.open(); }); + it('[TC_006] should verify whether the current user can create a TAAS project', async () => { + await CreateProjectPageHelper.verifyTaasProject(testData.taas); + }); + it('[TC_001] should verify whether the current user can create a Design, Development & Deployment project', async () => { await CreateProjectPageHelper.verifyProjectCreation(testData.projectData); }); diff --git a/connect-automation/utils/config-helper.ts b/connect-automation/utils/config-helper.ts index 99df6c111..526b55743 100644 --- a/connect-automation/utils/config-helper.ts +++ b/connect-automation/utils/config-helper.ts @@ -119,4 +119,11 @@ export const ConfigHelper = { getExpiredProjectUrl(): string { return this.getConfig().expiredProjectUrl; }, + + /** + * Get platform URL + */ + getPlatformUrl(): string { + return this.getConfig().platformUrl; + }, }; diff --git a/src/assets/icons/icon-check-thin.svg b/src/assets/icons/icon-check-thin.svg new file mode 100644 index 000000000..693c14617 --- /dev/null +++ b/src/assets/icons/icon-check-thin.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/icon-dots.svg b/src/assets/icons/icon-dots.svg new file mode 100644 index 000000000..89a3cfcf6 --- /dev/null +++ b/src/assets/icons/icon-dots.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/icon-gnatt-gray.svg b/src/assets/icons/icon-gnatt-gray.svg new file mode 100644 index 000000000..593fbd1fe --- /dev/null +++ b/src/assets/icons/icon-gnatt-gray.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/icon-x-mark-thin.svg b/src/assets/icons/icon-x-mark-thin.svg new file mode 100644 index 000000000..10d836ee8 --- /dev/null +++ b/src/assets/icons/icon-x-mark-thin.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/x-mark-thin.svg b/src/assets/icons/x-mark-thin.svg new file mode 100644 index 000000000..055951388 --- /dev/null +++ b/src/assets/icons/x-mark-thin.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/Layout/Layout.jsx b/src/components/Layout/Layout.jsx index a71cfc7ef..b3258fce4 100644 --- a/src/components/Layout/Layout.jsx +++ b/src/components/Layout/Layout.jsx @@ -29,6 +29,7 @@ const Layout = (props) => {