Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix project creation w/ tests #402

Merged
merged 15 commits into from
Jun 19, 2024
29 changes: 21 additions & 8 deletions apps/new/widget/page/projects/Editor.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
const accountId = context.accountId;

if (!context.accountId) {
return (
<Widget
src="${config_account}/widget/components.LoginAction"
loading=""
props={{
text: "Please log in in order to see create or edit a project.",
}}
/>
);
}

const { Button, InputField, TextEditor, Modal } = VM.require(
"${alias_old}/widget/components",
) || {
Expand Down Expand Up @@ -661,7 +674,7 @@ const SecondScreen = () => {
src="${alias_old}/widget/components.UploadField"
props={{
image: avatar,
onChange: (image) => setAvatar({ image }),
onChange: (image) => setAvatar(image),
}}
/>
</div>
Expand All @@ -671,7 +684,7 @@ const SecondScreen = () => {
src="${alias_old}/widget/components.UploadField"
props={{
image: coverImage,
onChange: (image) => setCoverImage({ image }),
onChange: (image) => setCoverImage(image),
}}
/>
</div>
Expand Down Expand Up @@ -723,7 +736,11 @@ const SecondScreen = () => {
Back
</Button>

<Button variant="primary" onClick={onCreateProject}>
<Button
variant="primary"
onClick={onCreateProject}
disabled={invalidContributorFound}
>
{isEditScreen ? "Save Changes" : "Create"}
</Button>
</div>
Expand Down Expand Up @@ -880,11 +897,7 @@ const FirstScreen = () => {
<Button
variant="primary"
disabled={
invalidContributorFound ||
invalidProjectAccount ||
!title ||
!description ||
!projectAccount
invalidProjectAccount || !title || !description || !projectAccount
}
onClick={() => setCurrentScreen(2)}
>
Expand Down
5 changes: 4 additions & 1 deletion apps/new/widget/page/projects/ImportAndCreateModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ return (
onOpenChange={toggleModal}
toggle={toggle}
>
<Container className="d-flex flex-column gap-4 my-2">
<Container
className="d-flex flex-column gap-4 my-2"
data-testid="create-project-modal"
>
<Item
title="Create my own project"
description="Create your own completely new project, customize it your way!"
Expand Down
3 changes: 2 additions & 1 deletion apps/old/widget/components/InputField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ function InputField({
key={`input-container-${key}`}
style={{ maxWidth: maxWidth ?? "390px" }}
>
{label && <Label>{label}</Label>}
{label && <Label htmlFor={label}>{label}</Label>}
<InputWrapper style={{ maxWidth: maxWidth ?? "390px" }}>
{prefix && <PrefixContainer>{prefix}</PrefixContainer>}
<Input
id={label}
key={`input-field-${key}`}
value={value}
className={error ? "invalid" : ""}
Expand Down
8 changes: 5 additions & 3 deletions apps/old/widget/components/UploadField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ const uploadFile = (files) => {
})
.then((res) => {
setImg(res.body.cid);
props.setImage({
ipfs_cid: res.body.cid,
});
if (props.onChange) {
props.onChange({
ipfs_cid: res.body.cid,
});
}
});
};

Expand Down
12 changes: 5 additions & 7 deletions playwright-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,15 @@ It is encouraged to include video in pull requests in order to demonstrate funct
Currently, none of the tests post actual transactions to the smart contracts. Still you should try writing your tests so that they do the actual function call, but just skip the final step of sending the transaction. You can do this by capturing the transaction confirmation popup provided by the NEAR social VM.

```javascript
const expectedTransactionData = {};

// click button that triggers transaction
await page.getByRole("button", { name: "Donate" }).nth(1).click();
await page.getByRole("button", { name: "Create" }).nth(1).click();

const transactionObj = JSON.parse(await page.locator("div.modal-body code").innerText());

// do something with transactionObj
expect(transactionObj).toMatchObject({
amount: 100,
message: "",
projectId: DEFAULT_PROJECT_ID,
});
expect(transactionObj).toMatchObject(expectedTransactionData);
```

See the test called "project with no active pot should donate direct with correct amount" in donate.spec.js for a full example.
See the test called "should complete flow and save data correctly with images populated" in editor.spec.js for a full example.
Binary file added playwright-tests/tests/assets/black.png
Megha-Dev-19 marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
232 changes: 232 additions & 0 deletions playwright-tests/tests/editor.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import { expect, test } from "@playwright/test";
import path from "path";
import { ROOT_SRC } from "../util/constants";

test.describe("?page=projects&tab=editor", () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/${ROOT_SRC}?page=projects&tab=editor`);
});

test.describe("User is not logged in", () => {
test.use({
storageState: "playwright-tests/storage-states/wallet-not-connected.json",
});

test("editor page should prompt user to log in", async ({ page }) => {
const requireLogin = await page.getByText(
"Please log in in order to see create or edit a project.",
);

await expect(requireLogin).toBeVisible();
});
});

test.describe("User is logged in", () => {
test.use({
storageState: "playwright-tests/storage-states/wallet-connected.json",
});

test.beforeEach(async ({ page }) => {
// Intercept IPFS requests
await page.route("**/add", async (route) => {
Comment on lines +29 to +31
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we running this before each test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used to mock the IPFS upload -- I'm returning a dummy cid for black.png

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but do we need to run it before each test?, not sure how many tests do we have under this.

Copy link
Contributor Author

@elliotBraem elliotBraem Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you're right -- next time I make a change here, I'll clean it up and move it in the test itself

const modifiedResponse = {
status: 200,
contentType: "application/json",
body: JSON.stringify({ cid: "simple_cid" }),
};

// Fulfill the route with the modified response
await route.fulfill(modifiedResponse);
});
});

test("should not allow next when empty required fields", async ({
page,
}) => {
const nextButton = await page.getByRole("button", { name: "Next" });
await expect(nextButton).toBeDisabled();

const projectAccountAddress = await page.getByPlaceholder(
"Enter Project Account Address",
);

const title = await page.getByPlaceholder("Enter Project Title");
const description = await page
.frameLocator("iframe")
.locator('textarea[name="textarea"]');

// Fill required fields
await projectAccountAddress.fill("anyproject.near");
await title.fill("Sample project");

await description.click();
await description.fill("This is a sample project");

await expect(nextButton).toBeEnabled();

// Clear title
await title.clear();
await expect(nextButton).toBeDisabled();

await title.fill("Sample project");
await expect(nextButton).toBeEnabled();

await description.click();
await description.clear();
await expect(nextButton).toBeDisabled();
});

test("should not allow invalid project account address", async ({
page,
}) => {
// Project Account Address
await page
.getByPlaceholder("Enter Project Account Address")
.fill("anyproject");

const errorMsg = await page.getByText(
"Invalid Near Address, please enter a valid near address",
);
await expect(errorMsg).toBeVisible();
});

test("cancel should navigate to main projects page", async ({ page }) => {
await page.getByRole("button", { name: "Cancel" }).click();
expect(page.url()).toContain("?page=projects");
});

test("should complete flow and save data correctly with images populated", async ({
page,
}) => {
const expectedProjectData = {
// TODO: We will want to get rid of this
title: "Sample project",
description: "This is a sample project",
profileImage: {
ipfs_cid: "simple_cid",
},
backgroundImage: {
ipfs_cid: "simple_cid",
},
tags: {
test: "",
},
linktree: {
twitter: "SampleTwitter",
github: "SampleGithub",
telegram: "SampleTelegram",
website: "https://www.samplewebsite.com",
},
// End remove
contributors: ["anybody.near", "nobody.near"],
tabs: ["overview", "tasks", "activity"],
projectAccountId: "anyproject.near",
teamSize: "1-10",
location: "anywhere",
};

const expectedTransactionData = {
"anybody.near": {
project: {
"sample-project": {
"": JSON.stringify(expectedProjectData),
metadata: {
name: "Sample project",
description: "This is a sample project",
image: {
ipfs_cid: "simple_cid",
},
backgroundImage: {
ipfs_cid: "simple_cid",
},
tags: {
test: "",
},
linktree: {
github: "https://github.com/SampleGithub",
telegram: "https://t.me/SampleTelegram",
twitter: "https://twitter.com/SampleTwitter",
website: "https://www.samplewebsite.com",
},
},
},
},
"builddao.testnet": {
project: {
"anybody.near_project_sample-project": "",
},
},
},
};

// Page one //

// Project Account Address
await page
.getByPlaceholder("Enter Project Account Address")
.fill("anyproject.near");
Megha-Dev-19 marked this conversation as resolved.
Show resolved Hide resolved

// Title
await page.getByPlaceholder("Enter Project Title").fill("Sample project");

// Description
await page
.frameLocator("iframe")
.locator('textarea[name="textarea"]')
.click();
await page
.frameLocator("iframe")
.locator('textarea[name="textarea"]')
.fill("This is a sample project");

await page.getByPlaceholder("Enter location").fill("anywhere"); // Location

await page.getByRole("combobox").selectOption("1-10");

await page.getByLabel("Twitter").fill("SampleTwitter");
await page.getByLabel("Github").fill("SampleGithub");
await page.getByLabel("Telegram").fill("SampleTelegram");
await page.getByLabel("Website").fill("https://www.samplewebsite.com");

// Next page
await page.getByRole("button", { name: "Next" }).click();

// Page two //

// Contributors
await page.getByRole("combobox").nth(0).click();
await page.getByRole("combobox").nth(0).fill("nobody.near");
await page.getByLabel("nobody.near").click();

// Avatar
const avatarInput = await page.locator("input[type=file]").nth(0);
await avatarInput.setInputFiles(
path.join(__dirname, "./assets/black.png"),
);

// Background
const backgroundInput = await page.locator("input[type=file]").nth(1);
await backgroundInput.setInputFiles(
path.join(__dirname, "./assets/black.png"),
);

await page.getByLabel("Updates Feed").uncheck();
await page.getByLabel("Feedback Feed").uncheck();

await page.getByRole("combobox").nth(1).click();
await page.getByRole("combobox").nth(1).fill("test");
await page.getByLabel("test").click();

await page.getByRole("button", { name: "Create" }).click();
await page.getByRole("dialog").getByLabel("Close").click();

// click button that triggers transaction
await page.getByRole("button", { name: "Create" }).nth(0).click();
const transactionObj = JSON.parse(
await page.locator("div.modal-body code").innerText(),
);
// do something with transactionObj
expect(transactionObj).toMatchObject(expectedTransactionData);
});
});
});
Loading
Loading