📝 (index.tsx): add convertTestName function to utils.ts to convert card names to test ids
📝 (index.tsx): add `data-testid` attribute to Card component to improve testability 📝 (index.tsx): remove unnecessary parentheses in ternary operator 📝 (index.tsx): remove unnecessary `undefined` in ternary operator 📝 (index.tsx): add `data-testid` attribute to delete button to improve testability 📝 (index.tsx): add `convertTestName` function to utils.ts to convert card names to test ids 📝 (utils.ts): add `convertTestName` function to convert card names to test ids 📝 (deleteComponentFlows.spec.ts): add end-to-end tests for deleting a flow and a component
This commit is contained in:
parent
8121151a8f
commit
5ef34e48f3
3 changed files with 94 additions and 43 deletions
|
|
@ -8,7 +8,7 @@ import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||||
import { useStoreStore } from "../../stores/storeStore";
|
import { useStoreStore } from "../../stores/storeStore";
|
||||||
import { storeComponent } from "../../types/store";
|
import { storeComponent } from "../../types/store";
|
||||||
import cloneFLowWithParent from "../../utils/storeUtils";
|
import cloneFLowWithParent from "../../utils/storeUtils";
|
||||||
import { cn } from "../../utils/utils";
|
import { cn, convertTestName } from "../../utils/utils";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
import ShadTooltip from "../shadTooltipComponent";
|
import ShadTooltip from "../shadTooltipComponent";
|
||||||
import { Badge } from "../ui/badge";
|
import { Badge } from "../ui/badge";
|
||||||
|
|
@ -48,11 +48,11 @@ export default function CollectionCardComponent({
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [loadingLike, setLoadingLike] = useState(false);
|
const [loadingLike, setLoadingLike] = useState(false);
|
||||||
const [liked_by_user, setLiked_by_user] = useState(
|
const [liked_by_user, setLiked_by_user] = useState(
|
||||||
data?.liked_by_user ?? false
|
data?.liked_by_user ?? false,
|
||||||
);
|
);
|
||||||
const [likes_count, setLikes_count] = useState(data?.liked_by_count ?? 0);
|
const [likes_count, setLikes_count] = useState(data?.liked_by_count ?? 0);
|
||||||
const [downloads_count, setDownloads_count] = useState(
|
const [downloads_count, setDownloads_count] = useState(
|
||||||
data?.downloads_count ?? 0
|
data?.downloads_count ?? 0,
|
||||||
);
|
);
|
||||||
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||||
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
|
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
|
||||||
|
|
@ -63,7 +63,7 @@ export default function CollectionCardComponent({
|
||||||
const [openPlayground, setOpenPlayground] = useState(false);
|
const [openPlayground, setOpenPlayground] = useState(false);
|
||||||
const [openDelete, setOpenDelete] = useState(false);
|
const [openDelete, setOpenDelete] = useState(false);
|
||||||
const setCurrentFlowId = useFlowsManagerStore(
|
const setCurrentFlowId = useFlowsManagerStore(
|
||||||
(state) => state.setCurrentFlowId
|
(state) => state.setCurrentFlowId,
|
||||||
);
|
);
|
||||||
const [loadingPlayground, setLoadingPlayground] = useState(false);
|
const [loadingPlayground, setLoadingPlayground] = useState(false);
|
||||||
|
|
||||||
|
|
@ -106,16 +106,18 @@ export default function CollectionCardComponent({
|
||||||
addFlow(true, newFlow)
|
addFlow(true, newFlow)
|
||||||
.then((id) => {
|
.then((id) => {
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: `${name} ${isStore ? "Downloaded" : "Installed"
|
title: `${name} ${
|
||||||
} Successfully.`,
|
isStore ? "Downloaded" : "Installed"
|
||||||
|
} Successfully.`,
|
||||||
});
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setErrorData({
|
setErrorData({
|
||||||
title: `Error ${isStore ? "downloading" : "installing"
|
title: `Error ${
|
||||||
} the ${name}`,
|
isStore ? "downloading" : "installing"
|
||||||
|
} the ${name}`,
|
||||||
list: [error["response"]["data"]["detail"]],
|
list: [error["response"]["data"]["detail"]],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -167,10 +169,11 @@ export default function CollectionCardComponent({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card
|
<Card
|
||||||
|
data-testid={`card-${convertTestName(data.name)}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group relative flex min-h-[11rem] flex-col justify-between overflow-hidden transition-all hover:shadow-md",
|
"group relative flex min-h-[11rem] flex-col justify-between overflow-hidden transition-all hover:shadow-md",
|
||||||
disabled ? "pointer-events-none opacity-50" : "",
|
disabled ? "pointer-events-none opacity-50" : "",
|
||||||
onClick ? "cursor-pointer" : ""
|
onClick ? "cursor-pointer" : "",
|
||||||
)}
|
)}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
|
|
@ -183,7 +186,7 @@ export default function CollectionCardComponent({
|
||||||
"flex-shrink-0",
|
"flex-shrink-0",
|
||||||
data.is_component
|
data.is_component
|
||||||
? "mx-0.5 h-6 w-6 text-component-icon"
|
? "mx-0.5 h-6 w-6 text-component-icon"
|
||||||
: "h-7 w-7 flex-shrink-0 text-flow-icon"
|
: "h-7 w-7 flex-shrink-0 text-flow-icon",
|
||||||
)}
|
)}
|
||||||
name={data.is_component ? "ToyBrick" : "Group"}
|
name={data.is_component ? "ToyBrick" : "Group"}
|
||||||
/>
|
/>
|
||||||
|
|
@ -235,17 +238,17 @@ export default function CollectionCardComponent({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{onDelete && data?.metadata === undefined && (
|
{onDelete && data?.metadata === undefined && (
|
||||||
<button onClick={(e) => {
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<IconComponent
|
||||||
<IconComponent
|
name="Trash2"
|
||||||
name="Trash2"
|
className="h-5 w-5 text-primary opacity-0 transition-all hover:text-destructive group-hover:opacity-100"
|
||||||
className="h-5 w-5 text-primary opacity-0 transition-all hover:text-destructive group-hover:opacity-100"
|
/>
|
||||||
/>
|
</button>
|
||||||
</button>
|
|
||||||
)}
|
)}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -326,9 +329,7 @@ export default function CollectionCardComponent({
|
||||||
)}
|
)}
|
||||||
Playground
|
Playground
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : undefined}
|
||||||
undefined
|
|
||||||
)}
|
|
||||||
{data.liked_by_count != undefined && (
|
{data.liked_by_count != undefined && (
|
||||||
<div className="flex gap-0.5">
|
<div className="flex gap-0.5">
|
||||||
{onDelete && data?.metadata !== undefined ? (
|
{onDelete && data?.metadata !== undefined ? (
|
||||||
|
|
@ -351,10 +352,11 @@ export default function CollectionCardComponent({
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
|
data-testid={`delete-${convertTestName(data.name)}`}
|
||||||
name="Trash2"
|
name="Trash2"
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-5 w-5",
|
"h-5 w-5",
|
||||||
!authorized ? " text-ring" : ""
|
!authorized ? " text-ring" : "",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -389,7 +391,7 @@ export default function CollectionCardComponent({
|
||||||
liked_by_user
|
liked_by_user
|
||||||
? "fill-destructive stroke-destructive"
|
? "fill-destructive stroke-destructive"
|
||||||
: "",
|
: "",
|
||||||
!authorized ? " text-ring" : ""
|
!authorized ? " text-ring" : "",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -427,7 +429,7 @@ export default function CollectionCardComponent({
|
||||||
}
|
}
|
||||||
className={cn(
|
className={cn(
|
||||||
loading ? "h-5 w-5 animate-spin" : "h-5 w-5",
|
loading ? "h-5 w-5 animate-spin" : "h-5 w-5",
|
||||||
!authorized ? " text-ring" : ""
|
!authorized ? " text-ring" : "",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -490,13 +492,12 @@ export default function CollectionCardComponent({
|
||||||
open={openDelete}
|
open={openDelete}
|
||||||
setOpen={setOpenDelete}
|
setOpen={setOpenDelete}
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
if(onDelete) onDelete();
|
if (onDelete) onDelete();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<></>
|
<></>
|
||||||
</DeleteConfirmationModal>
|
</DeleteConfirmationModal>
|
||||||
)
|
)}
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export function normalCaseToSnakeCase(str: string): string {
|
||||||
|
|
||||||
export function toTitleCase(
|
export function toTitleCase(
|
||||||
str: string | undefined,
|
str: string | undefined,
|
||||||
isNodeField?: boolean
|
isNodeField?: boolean,
|
||||||
): string {
|
): string {
|
||||||
if (!str) return "";
|
if (!str) return "";
|
||||||
let result = str
|
let result = str
|
||||||
|
|
@ -70,7 +70,7 @@ export function toTitleCase(
|
||||||
if (isNodeField) return word;
|
if (isNodeField) return word;
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
return checkUpperWords(
|
return checkUpperWords(
|
||||||
word[0].toUpperCase() + word.slice(1).toLowerCase()
|
word[0].toUpperCase() + word.slice(1).toLowerCase(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return checkUpperWords(word.toLowerCase());
|
return checkUpperWords(word.toLowerCase());
|
||||||
|
|
@ -83,7 +83,7 @@ export function toTitleCase(
|
||||||
if (isNodeField) return word;
|
if (isNodeField) return word;
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
return checkUpperWords(
|
return checkUpperWords(
|
||||||
word[0].toUpperCase() + word.slice(1).toLowerCase()
|
word[0].toUpperCase() + word.slice(1).toLowerCase(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return checkUpperWords(word.toLowerCase());
|
return checkUpperWords(word.toLowerCase());
|
||||||
|
|
@ -93,8 +93,8 @@ export function toTitleCase(
|
||||||
|
|
||||||
export function getUnavailableFields(variables: {
|
export function getUnavailableFields(variables: {
|
||||||
[key: string]: { default_fields?: string[] };
|
[key: string]: { default_fields?: string[] };
|
||||||
}): {[name: string]: string} {
|
}): { [name: string]: string } {
|
||||||
const unVariables:{[name: string]: string} = {};
|
const unVariables: { [name: string]: string } = {};
|
||||||
Object.keys(variables).forEach((key) => {
|
Object.keys(variables).forEach((key) => {
|
||||||
if (variables[key].default_fields) {
|
if (variables[key].default_fields) {
|
||||||
variables[key].default_fields!.forEach((field) => {
|
variables[key].default_fields!.forEach((field) => {
|
||||||
|
|
@ -123,7 +123,7 @@ export function groupByFamily(
|
||||||
data: APIDataType,
|
data: APIDataType,
|
||||||
baseClasses: string,
|
baseClasses: string,
|
||||||
left: boolean,
|
left: boolean,
|
||||||
flow?: NodeType[]
|
flow?: NodeType[],
|
||||||
): groupedObjType[] {
|
): groupedObjType[] {
|
||||||
const baseClassesSet = new Set(baseClasses.split("\n"));
|
const baseClassesSet = new Set(baseClasses.split("\n"));
|
||||||
let arrOfPossibleInputs: Array<{
|
let arrOfPossibleInputs: Array<{
|
||||||
|
|
@ -149,7 +149,7 @@ export function groupByFamily(
|
||||||
baseClassesSet.has(template.type)) ||
|
baseClassesSet.has(template.type)) ||
|
||||||
(template.input_types &&
|
(template.input_types &&
|
||||||
template.input_types.some((inputType) =>
|
template.input_types.some((inputType) =>
|
||||||
baseClassesSet.has(inputType)
|
baseClassesSet.has(inputType),
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
@ -169,7 +169,7 @@ export function groupByFamily(
|
||||||
hasBaseClassInBaseClasses:
|
hasBaseClassInBaseClasses:
|
||||||
foundNode?.hasBaseClassInBaseClasses ||
|
foundNode?.hasBaseClassInBaseClasses ||
|
||||||
nodeData.node!.base_classes.some((baseClass) =>
|
nodeData.node!.base_classes.some((baseClass) =>
|
||||||
baseClassesSet.has(baseClass)
|
baseClassesSet.has(baseClass),
|
||||||
), //seta como anterior ou verifica se o node tem base class
|
), //seta como anterior ou verifica se o node tem base class
|
||||||
displayName: nodeData.node?.display_name,
|
displayName: nodeData.node?.display_name,
|
||||||
});
|
});
|
||||||
|
|
@ -186,10 +186,10 @@ export function groupByFamily(
|
||||||
if (!foundNode) {
|
if (!foundNode) {
|
||||||
foundNode = {
|
foundNode = {
|
||||||
hasBaseClassInTemplate: Object.values(node!.template).some(
|
hasBaseClassInTemplate: Object.values(node!.template).some(
|
||||||
checkBaseClass
|
checkBaseClass,
|
||||||
),
|
),
|
||||||
hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) =>
|
hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) =>
|
||||||
baseClassesSet.has(baseClass)
|
baseClassesSet.has(baseClass),
|
||||||
),
|
),
|
||||||
displayName: node?.display_name,
|
displayName: node?.display_name,
|
||||||
};
|
};
|
||||||
|
|
@ -246,7 +246,7 @@ export function getRandomDescription(): string {
|
||||||
export function getRandomName(
|
export function getRandomName(
|
||||||
retry: number = 0,
|
retry: number = 0,
|
||||||
noSpace: boolean = false,
|
noSpace: boolean = false,
|
||||||
maxRetries: number = 3
|
maxRetries: number = 3,
|
||||||
): string {
|
): string {
|
||||||
const left: string[] = ADJECTIVES;
|
const left: string[] = ADJECTIVES;
|
||||||
const right: string[] = NOUNS;
|
const right: string[] = NOUNS;
|
||||||
|
|
@ -325,7 +325,7 @@ export function getChatInputField(flowState?: FlowState) {
|
||||||
export function getPythonApiCode(
|
export function getPythonApiCode(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
tweak?: any[]
|
tweak?: any[],
|
||||||
): string {
|
): string {
|
||||||
const flowId = flow.id;
|
const flowId = flow.id;
|
||||||
|
|
||||||
|
|
@ -393,7 +393,7 @@ print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${
|
||||||
export function getCurlCode(
|
export function getCurlCode(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
tweak?: any[]
|
tweak?: any[],
|
||||||
): string {
|
): string {
|
||||||
const flowId = flow.id;
|
const flowId = flow.id;
|
||||||
const tweaks = buildTweaks(flow);
|
const tweaks = buildTweaks(flow);
|
||||||
|
|
@ -463,7 +463,7 @@ result = run_flow_from_json(flow="${flowName}.json",
|
||||||
export function getWidgetCode(
|
export function getWidgetCode(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
flowState?: FlowState
|
flowState?: FlowState,
|
||||||
): string {
|
): string {
|
||||||
const flowId = flow.id;
|
const flowId = flow.id;
|
||||||
const flowName = flow.name;
|
const flowName = flow.name;
|
||||||
|
|
@ -593,7 +593,7 @@ export function checkLocalStorageKey(key: string): boolean {
|
||||||
|
|
||||||
export function IncrementObjectKey(
|
export function IncrementObjectKey(
|
||||||
object: object,
|
object: object,
|
||||||
key: string
|
key: string,
|
||||||
): { newKey: string; increment: number } {
|
): { newKey: string; increment: number } {
|
||||||
let count = 1;
|
let count = 1;
|
||||||
const type = removeCountFromString(key);
|
const type = removeCountFromString(key);
|
||||||
|
|
@ -665,7 +665,7 @@ export function getSetFromObject(obj: object, key?: string): Set<string> {
|
||||||
|
|
||||||
export function getFieldTitle(
|
export function getFieldTitle(
|
||||||
template: APITemplateType,
|
template: APITemplateType,
|
||||||
templateField: string
|
templateField: string,
|
||||||
): string {
|
): string {
|
||||||
return template[templateField].display_name
|
return template[templateField].display_name
|
||||||
? template[templateField].display_name!
|
? template[templateField].display_name!
|
||||||
|
|
@ -715,3 +715,7 @@ export function freezeObject(obj: any) {
|
||||||
if (!obj) return obj;
|
if (!obj) return obj;
|
||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function convertTestName(name: string): string {
|
||||||
|
return name.replace(/ /g, "-").toLowerCase();
|
||||||
|
}
|
||||||
|
|
|
||||||
46
src/frontend/tests/end-to-end/deleteComponentFlows.spec.ts
Normal file
46
src/frontend/tests/end-to-end/deleteComponentFlows.spec.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { test } from "@playwright/test";
|
||||||
|
|
||||||
|
test("shoud delete a flow", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
await page.getByText("Store").nth(0).click();
|
||||||
|
await page.getByTestId("install-Website Content QA").click();
|
||||||
|
await page.waitForTimeout(5000);
|
||||||
|
await page.getByText("My Collection").nth(0).click();
|
||||||
|
await page.getByText("Website Content QA").first().isVisible();
|
||||||
|
await page
|
||||||
|
.getByTestId("card-website-content-qa")
|
||||||
|
.first()
|
||||||
|
.hover()
|
||||||
|
.then(async () => {
|
||||||
|
await page.getByTestId("icon-Trash2").first().click();
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
});
|
||||||
|
await page.getByText("Confirm deletion of component?").isVisible();
|
||||||
|
await page.getByText("Delete").nth(1).click();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
await page.getByText("Successfully").first().isVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shoud delete a component", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
await page.getByText("Store").nth(0).click();
|
||||||
|
await page.getByTestId("install-Basic RAG").click();
|
||||||
|
await page.waitForTimeout(5000);
|
||||||
|
await page.getByText("My Collection").nth(0).click();
|
||||||
|
await page.getByText("Components").first().click();
|
||||||
|
await page.getByText("Basic RAG").first().isVisible();
|
||||||
|
await page
|
||||||
|
.getByTestId("card-basic-rag")
|
||||||
|
.first()
|
||||||
|
.hover()
|
||||||
|
.then(async () => {
|
||||||
|
await page.getByTestId("icon-Trash2").first().click();
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
});
|
||||||
|
await page.getByText("Confirm deletion of component?").isVisible();
|
||||||
|
await page.getByText("Delete").nth(1).click();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
await page.getByText("Successfully").first().isVisible();
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue