📝 (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:
cristhianzl 2024-05-03 10:16:24 -03:00
commit 5ef34e48f3
3 changed files with 94 additions and 43 deletions

View file

@ -8,7 +8,7 @@ import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { useStoreStore } from "../../stores/storeStore";
import { storeComponent } from "../../types/store";
import cloneFLowWithParent from "../../utils/storeUtils";
import { cn } from "../../utils/utils";
import { cn, convertTestName } from "../../utils/utils";
import IconComponent from "../genericIconComponent";
import ShadTooltip from "../shadTooltipComponent";
import { Badge } from "../ui/badge";
@ -48,11 +48,11 @@ export default function CollectionCardComponent({
const [loading, setLoading] = useState(false);
const [loadingLike, setLoadingLike] = useState(false);
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 [downloads_count, setDownloads_count] = useState(
data?.downloads_count ?? 0
data?.downloads_count ?? 0,
);
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
@ -63,7 +63,7 @@ export default function CollectionCardComponent({
const [openPlayground, setOpenPlayground] = useState(false);
const [openDelete, setOpenDelete] = useState(false);
const setCurrentFlowId = useFlowsManagerStore(
(state) => state.setCurrentFlowId
(state) => state.setCurrentFlowId,
);
const [loadingPlayground, setLoadingPlayground] = useState(false);
@ -106,16 +106,18 @@ export default function CollectionCardComponent({
addFlow(true, newFlow)
.then((id) => {
setSuccessData({
title: `${name} ${isStore ? "Downloaded" : "Installed"
} Successfully.`,
title: `${name} ${
isStore ? "Downloaded" : "Installed"
} Successfully.`,
});
setLoading(false);
})
.catch((error) => {
setLoading(false);
setErrorData({
title: `Error ${isStore ? "downloading" : "installing"
} the ${name}`,
title: `Error ${
isStore ? "downloading" : "installing"
} the ${name}`,
list: [error["response"]["data"]["detail"]],
});
});
@ -167,10 +169,11 @@ export default function CollectionCardComponent({
return (
<>
<Card
data-testid={`card-${convertTestName(data.name)}`}
className={cn(
"group relative flex min-h-[11rem] flex-col justify-between overflow-hidden transition-all hover:shadow-md",
disabled ? "pointer-events-none opacity-50" : "",
onClick ? "cursor-pointer" : ""
onClick ? "cursor-pointer" : "",
)}
onClick={onClick}
>
@ -183,7 +186,7 @@ export default function CollectionCardComponent({
"flex-shrink-0",
data.is_component
? "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"}
/>
@ -235,17 +238,17 @@ export default function CollectionCardComponent({
)}
{onDelete && data?.metadata === undefined && (
<button onClick={(e) => {
<button
onClick={(e) => {
e.stopPropagation();
setOpenDelete(true);
}}
>
<IconComponent
name="Trash2"
className="h-5 w-5 text-primary opacity-0 transition-all hover:text-destructive group-hover:opacity-100"
/>
</button>
>
<IconComponent
name="Trash2"
className="h-5 w-5 text-primary opacity-0 transition-all hover:text-destructive group-hover:opacity-100"
/>
</button>
)}
</CardTitle>
</div>
@ -326,9 +329,7 @@ export default function CollectionCardComponent({
)}
Playground
</Button>
) : (
undefined
)}
) : undefined}
{data.liked_by_count != undefined && (
<div className="flex gap-0.5">
{onDelete && data?.metadata !== undefined ? (
@ -351,10 +352,11 @@ export default function CollectionCardComponent({
}
>
<IconComponent
data-testid={`delete-${convertTestName(data.name)}`}
name="Trash2"
className={cn(
"h-5 w-5",
!authorized ? " text-ring" : ""
!authorized ? " text-ring" : "",
)}
/>
</Button>
@ -389,7 +391,7 @@ export default function CollectionCardComponent({
liked_by_user
? "fill-destructive stroke-destructive"
: "",
!authorized ? " text-ring" : ""
!authorized ? " text-ring" : "",
)}
/>
</Button>
@ -427,7 +429,7 @@ export default function CollectionCardComponent({
}
className={cn(
loading ? "h-5 w-5 animate-spin" : "h-5 w-5",
!authorized ? " text-ring" : ""
!authorized ? " text-ring" : "",
)}
/>
</Button>
@ -490,13 +492,12 @@ export default function CollectionCardComponent({
open={openDelete}
setOpen={setOpenDelete}
onConfirm={() => {
if(onDelete) onDelete();
if (onDelete) onDelete();
}}
>
<></>
</DeleteConfirmationModal>
)
}
)}
</>
);
}

View file

@ -61,7 +61,7 @@ export function normalCaseToSnakeCase(str: string): string {
export function toTitleCase(
str: string | undefined,
isNodeField?: boolean
isNodeField?: boolean,
): string {
if (!str) return "";
let result = str
@ -70,7 +70,7 @@ export function toTitleCase(
if (isNodeField) return word;
if (index === 0) {
return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase()
word[0].toUpperCase() + word.slice(1).toLowerCase(),
);
}
return checkUpperWords(word.toLowerCase());
@ -83,7 +83,7 @@ export function toTitleCase(
if (isNodeField) return word;
if (index === 0) {
return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase()
word[0].toUpperCase() + word.slice(1).toLowerCase(),
);
}
return checkUpperWords(word.toLowerCase());
@ -93,8 +93,8 @@ export function toTitleCase(
export function getUnavailableFields(variables: {
[key: string]: { default_fields?: string[] };
}): {[name: string]: string} {
const unVariables:{[name: string]: string} = {};
}): { [name: string]: string } {
const unVariables: { [name: string]: string } = {};
Object.keys(variables).forEach((key) => {
if (variables[key].default_fields) {
variables[key].default_fields!.forEach((field) => {
@ -123,7 +123,7 @@ export function groupByFamily(
data: APIDataType,
baseClasses: string,
left: boolean,
flow?: NodeType[]
flow?: NodeType[],
): groupedObjType[] {
const baseClassesSet = new Set(baseClasses.split("\n"));
let arrOfPossibleInputs: Array<{
@ -149,7 +149,7 @@ export function groupByFamily(
baseClassesSet.has(template.type)) ||
(template.input_types &&
template.input_types.some((inputType) =>
baseClassesSet.has(inputType)
baseClassesSet.has(inputType),
)))
);
};
@ -169,7 +169,7 @@ export function groupByFamily(
hasBaseClassInBaseClasses:
foundNode?.hasBaseClassInBaseClasses ||
nodeData.node!.base_classes.some((baseClass) =>
baseClassesSet.has(baseClass)
baseClassesSet.has(baseClass),
), //seta como anterior ou verifica se o node tem base class
displayName: nodeData.node?.display_name,
});
@ -186,10 +186,10 @@ export function groupByFamily(
if (!foundNode) {
foundNode = {
hasBaseClassInTemplate: Object.values(node!.template).some(
checkBaseClass
checkBaseClass,
),
hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) =>
baseClassesSet.has(baseClass)
baseClassesSet.has(baseClass),
),
displayName: node?.display_name,
};
@ -246,7 +246,7 @@ export function getRandomDescription(): string {
export function getRandomName(
retry: number = 0,
noSpace: boolean = false,
maxRetries: number = 3
maxRetries: number = 3,
): string {
const left: string[] = ADJECTIVES;
const right: string[] = NOUNS;
@ -325,7 +325,7 @@ export function getChatInputField(flowState?: FlowState) {
export function getPythonApiCode(
flow: FlowType,
isAuth: boolean,
tweak?: any[]
tweak?: any[],
): string {
const flowId = flow.id;
@ -393,7 +393,7 @@ print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${
export function getCurlCode(
flow: FlowType,
isAuth: boolean,
tweak?: any[]
tweak?: any[],
): string {
const flowId = flow.id;
const tweaks = buildTweaks(flow);
@ -463,7 +463,7 @@ result = run_flow_from_json(flow="${flowName}.json",
export function getWidgetCode(
flow: FlowType,
isAuth: boolean,
flowState?: FlowState
flowState?: FlowState,
): string {
const flowId = flow.id;
const flowName = flow.name;
@ -593,7 +593,7 @@ export function checkLocalStorageKey(key: string): boolean {
export function IncrementObjectKey(
object: object,
key: string
key: string,
): { newKey: string; increment: number } {
let count = 1;
const type = removeCountFromString(key);
@ -665,7 +665,7 @@ export function getSetFromObject(obj: object, key?: string): Set<string> {
export function getFieldTitle(
template: APITemplateType,
templateField: string
templateField: string,
): string {
return template[templateField].display_name
? template[templateField].display_name!
@ -715,3 +715,7 @@ export function freezeObject(obj: any) {
if (!obj) return obj;
return JSON.parse(JSON.stringify(obj));
}
export function convertTestName(name: string): string {
return name.replace(/ /g, "-").toLowerCase();
}

View 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();
});