Skip to content

Commit

Permalink
Merge pull request #1673 from jdi-testing/issue_1651-progress-bar-err…
Browse files Browse the repository at this point in the history
…or-state

issue_1651 progress bar error state
  • Loading branch information
bklimov-web authored Mar 26, 2024
2 parents fe5ec19 + e085402 commit 40f39dd
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 165 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "JDN — Page Object Generator",
"description": "JDN – helps Test Automation Engineer to create Page Objects in the test automation framework and speed up test development",
"devtools_page": "index.html",
"version": "3.15.12",
"version": "3.15.13",
"icons": {
"128": "icon128.png"
},
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jdn-ai-chrome-extension",
"version": "3.15.12",
"version": "3.15.13",
"description": "jdn-ai chrome extension",
"scripts": {
"start": "webpack --watch --env devenv",
Expand Down
85 changes: 44 additions & 41 deletions src/features/locators/components/LocatorsProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ import {
selectDeletedByPageObj,
selectFailedByPageObject,
} from '../selectors/locatorsFiltered.selectors';
import cn from 'classnames';

let timer: NodeJS.Timeout;

export const LocatorsProgress = () => {
const [isProgressActive, setIsProgressActive] = useState(false);
const generationStatus = useSelector((state: RootState) => state.locators.present.generationStatus);

const locatorsAll = useSelector((_state: RootState) => selectFilteredLocators(_state));
const generated = useSelector((_state: RootState) => selectCalculatedByPageObj(_state));
const inProgress = useSelector((_state: RootState) => selectInProgressByPageObj(_state));
const deleted = useSelector((_state: RootState) => selectDeletedByPageObj(_state));
const failed = useSelector((_state: RootState) => selectFailedByPageObject(_state));

const locatorsAll = useSelector(selectFilteredLocators);
const generated = useSelector(selectCalculatedByPageObj);
const inProgress = useSelector(selectInProgressByPageObj);
const deleted = useSelector(selectDeletedByPageObj);
const failed = useSelector(selectFailedByPageObject);
const calculationReady = size(generated);
const toBeCalculated = size(inProgress) + size(failed);
const total = size(locatorsAll) - size(deleted);
Expand Down Expand Up @@ -55,41 +55,44 @@ export const LocatorsProgress = () => {
return () => clearTimeout(timer);
}, [generated, inProgress, deleted]);

const shouldHideInfo = readinessPercentage !== 100 && generationStatus !== LocatorsGenerationStatus.failed;
const isGeneratedStatusFailed = generationStatus === LocatorsGenerationStatus.failed;

const className = cn({
'jdn__progress_hide-info': shouldHideInfo,
});

if (!isProgressActive) {
return null;
}

return (
<>
{isProgressActive ? (
<div className="jdn__locator-list-progress">
<div className="jdn__locator-list-progress-text">
{generationStatus === LocatorsGenerationStatus.failed ? (
<>
<Footnote>{LocatorGenerationMessage.failed}</Footnote>
<span className="ant-notification-notice-btn">
<Button type="text" size="small" onClick={handleRetry}>
Retry
</Button>
</span>
</>
) : (
<Footnote>
{size(inProgress)
? `${LocatorGenerationMessage.started} (${calculationReady}/${total})`
: size(failed)
? `${LocatorGenerationMessage.completeWithErrors} (${calculationReady}/${total})`
: `${LocatorGenerationMessage.complete}`}
</Footnote>
)}
</div>
<Progress
status={generationStatus === LocatorsGenerationStatus.failed ? 'exception' : undefined}
percent={readinessPercentage}
className={
readinessPercentage !== 100 && generationStatus !== LocatorsGenerationStatus.failed
? 'jdn__progress_hide-info'
: ''
}
/>
</div>
) : null}
</>
<div className="jdn__locator-list-progress">
<div className="jdn__locator-list-progress-text">
{isGeneratedStatusFailed ? (
<>
<Footnote>{LocatorGenerationMessage.failed}</Footnote>
<span className="ant-notification-notice-btn">
<Button type="text" size="small" onClick={handleRetry}>
Retry
</Button>
</span>
</>
) : (
<Footnote>
{size(inProgress)
? `${LocatorGenerationMessage.started} (${calculationReady}/${total})`
: size(failed)
? `${LocatorGenerationMessage.completeWithErrors} (${calculationReady}/${total})`
: `${LocatorGenerationMessage.complete}`}
</Footnote>
)}
</div>
<Progress
status={isGeneratedStatusFailed ? 'exception' : undefined}
percent={readinessPercentage}
className={className}
/>
</div>
);
};
28 changes: 18 additions & 10 deletions src/features/locators/reducers/identifyElements.thunk.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import type { ActionReducerMapBuilder, Middleware } from '@reduxjs/toolkit';
import { createAsyncThunk } from '@reduxjs/toolkit';
import { predictElements } from '../../../pageServices/pageDataHandlers';
import { findByRules, predictElements } from '../../../pageServices/pageDataHandlers';
import { IdentificationStatus, LocatorsState, PredictedEntity } from '../../locators/types/locator.types';
import { setCurrentPageObj, setPageData } from '../../pageObjects/pageObject.slice';
import { setFilter } from '../../filter/filter.slice';
import { PageObjectId } from '../../pageObjects/types/pageObjectSlice.types';
import { defaultLibrary, ElementLibrary, predictEndpoints } from '../types/generationClasses.types';

import { createLocators } from './createLocators.thunk';
import { findByRules } from '../utils/generationButton';
import { getLocalStorage, LocalStorageKey } from '../../../common/utils/localStorage';
import { selectAutoGeneratingLocatorTypes, selectPageObjById } from '../../pageObjects/selectors/pageObjects.selectors';
import { RootState } from '../../../app/store/store';
import { runLocatorsGeneration } from './runLocatorsGeneration.thunk';
import { finishProgressBar } from '../../pageObjects/progressBar.slice';
import { finishProgressBar, setProgressError } from '../../pageObjects/progressBar.slice';
import { delay } from '../utils/delay';
import { fetchPageDocument } from '../../../services/pageDocument/fetchPageDocument.thunk';
import { createDocumentForRobula } from '../../../services/pageDocument/pageDocument.slice';

interface Meta {
library: ElementLibrary;
pageObj: PageObjectId;
}

Expand All @@ -40,8 +38,17 @@ export const identifyElements = createAsyncThunk('locators/identifyElements', as
Then adds needed locators to state and runs locator value generation. */
try {
const endpoint = predictEndpoints[library];
const { data, pageData } =
library !== ElementLibrary.Vuetify ? await predictElements(endpoint) : await findByRules();
const { data, pageData, error } =
library === ElementLibrary.Vuetify ? await findByRules() : await predictElements(endpoint);

if (error) {
throw new Error(error);
}

if (!data) {
throw new Error('No data received from server');
}

const locators = data
.filter((el: PredictedEntity) => el.is_shown)
.map((el: PredictedEntity) => {
Expand All @@ -60,13 +67,15 @@ export const identifyElements = createAsyncThunk('locators/identifyElements', as
/* progress-bar finish animation delay: */
await delay(2000);

thunkAPI.dispatch(setPageData({ id: pageObj, pageData }));
if (pageData) {
thunkAPI.dispatch(setPageData({ id: pageObj, pageData }));
}

thunkAPI.dispatch(createLocators({ predictedElements: locators, library }));

return thunkAPI.fulfillWithValue(locators);
} catch (error) {
// can use params in the function so that when the progress bar is finished there will be information about errors
thunkAPI.dispatch(finishProgressBar());
thunkAPI.dispatch(setProgressError(error.message));
return thunkAPI.rejectWithValue(null);
}
});
Expand All @@ -77,7 +86,6 @@ export const identifyElementsReducer = (builder: ActionReducerMapBuilder<Locator
state.status = IdentificationStatus.loading;
})
.addCase(identifyElements.fulfilled, (state, { payload }) => {
// @ts-ignore
if (payload.length) state.status = IdentificationStatus.preparing;
else state.status = IdentificationStatus.noElements;
})
Expand Down
12 changes: 0 additions & 12 deletions src/features/locators/utils/generationButton.ts

This file was deleted.

34 changes: 9 additions & 25 deletions src/features/pageObjects/components/PageObjGenerationSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,10 @@ import { IN_DEVELOPMENT_TITLE } from '../../../common/constants/constants';

import { useOnboardingContext } from '../../onboarding/OnboardingProvider';
import { OnboardingStep } from '../../onboarding/constants';
import { useOnboarding } from '../../onboarding/useOnboarding';
import { resetProgressBar, startProgressBar } from '../progressBar.slice';
import { selectIsPageObjectsListUIEnabled } from '../selectors/pageObjectsListUI.selectors';
import { disablePageObjectsListUI } from '../pageObjectsListUI.slice';
import { OnboardingTooltip } from '../../onboarding/components/OnboardingTooltip';
import PageObjSettingsItem from './PageObjSettingsItem';

interface Props {
pageObj: PageObjectId;
library: ElementLibrary;
url: string;
}

// ToDo move to constants
const libraryOptions = [
{
Expand Down Expand Up @@ -98,27 +89,20 @@ const locatorTypeOptions = [
},
];

export const PageObjGenerationSettings: React.FC<Props> = ({ pageObj, library, url }) => {
interface Props {
pageObj: PageObjectId;
url: string;
isOnboardingOpen: boolean;
handleGenerate: () => void;
}

export const PageObjGenerationSettings: React.FC<Props> = ({ pageObj, url, handleGenerate, isOnboardingOpen }) => {
const status = useSelector((state: RootState) => state.locators.present.status);
const currentPageObject = useSelector(selectCurrentPageObject);
const pageObjects = useSelector(selectPageObjects);

const { isOnboardingOpen, handleOnChangeStep } = useOnboarding();

const dispatch = useDispatch<AppDispatch>();

const handleGenerate = () => {
if (isOnboardingOpen) handleOnChangeStep(OnboardingStep.Generating);
dispatch(setHideUnadded({ id: pageObj, hideUnadded: false }));
dispatch(identifyElements({ library, pageObj }));
// disable UI for PageObjList settings:
dispatch(disablePageObjectsListUI());
// reset to default progress bar:
dispatch(resetProgressBar());
// show and start progress bar:
dispatch(startProgressBar());
};

const refSettings = useRef<HTMLElement | null>(null);
const generationButtonRef = useRef<HTMLElement | null>(null);
const { updateStepRefs } = useOnboardingContext();
Expand Down Expand Up @@ -164,7 +148,7 @@ export const PageObjGenerationSettings: React.FC<Props> = ({ pageObj, library, u

const handleEmptyPO = () => {
dispatch(setHideUnadded({ id: pageObj, hideUnadded: true }));
dispatch(identifyElements({ library, pageObj }));
dispatch(identifyElements({ pageObj }));
};

const isLoading = () => isIdentificationLoading(status) && currentPageObject?.id === pageObj;
Expand Down
Loading

0 comments on commit 40f39dd

Please sign in to comment.