Skip to content

Commit

Permalink
e2e: Proposal Create mock structure.
Browse files Browse the repository at this point in the history
  • Loading branch information
vibros68 committed Dec 7, 2021
1 parent bed1ac4 commit 19e2970
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 52 deletions.
4 changes: 3 additions & 1 deletion src/components/DatePickerField/DatePickerField.jsx
Expand Up @@ -69,7 +69,9 @@ const DatePickerField = ({
};

return (
<div className={classNames("cursor-pointer", className)}>
<div
className={classNames("cursor-pointer", className)}
data-testid="datepicker">
<DatePicker
show={isOpen}
years={years}
Expand Down
2 changes: 2 additions & 0 deletions src/components/ProposalForm/ProposalForm.jsx
Expand Up @@ -308,6 +308,7 @@ const ProposalForm = React.memo(function ProposalForm({
<BoxTextInput
placeholder="Amount (USD)"
name="amount"
data-testid="proposal-amount"
tabIndex={1}
value={values.amount}
onChange={handleChangeWithTouched("amount")}
Expand Down Expand Up @@ -336,6 +337,7 @@ const ProposalForm = React.memo(function ProposalForm({
)}
<SelectField
name="domain"
id="proposal-domain-selector"
onChange={handleSelectFiledChange("domain")}
options={domainOptions}
className={classNames(styles.typeSelectWrapper, "margin-top-m")}
Expand Down
68 changes: 48 additions & 20 deletions teste2e/cypress/e2e/proposal/create.js
@@ -1,41 +1,69 @@
import { buildProposal } from "../../support/generate";

beforeEach(function mockApiCalls() {
// currently mocking pi and ticketvote summaries calls with any status, since
// they aren't used for assertions.
cy.useTicketvoteApi();
cy.useRecordsApi();
cy.usePiApi();
cy.useWwwApi();
cy.useCommentsApi();
});

describe("Proposal Create", () => {
// XXX This test needs changes in the Datepicker and (probably) the Select
// components, in order to fill the new form fields such as: start & end dates
// and amount - issue to track <insert issue link>
//
/*it("Paid user can create proposals manually", () => {
it("should allow paid user to create proposals", () => {
// paid user with proposal credits
const user = {
email: "adminuser@example.com",
username: "adminuser",
password: "password"
};
cy.userEnvironment("user", { verifyIdentity: true });
const proposal = buildProposal();
cy.login(user);
cy.visit("/");
cy.identity();
cy.recordsMiddleware("new", {});
cy.visit("/record/new");
cy.typeCreateProposal(proposal);
});*/
cy.findByRole("button", { name: /submit/i }).click();
// needs more time in general to complete this request so we increase the
// responseTimeout
cy.wait("@newProposal").should((xhr) => {
expect(xhr.status).to.equal(200);
cy.piMiddleware("summaries", { amountByStatus: { unvetted: 1 } });
const token = xhr.response.body.record.censorshiprecord.token;
cy.assertProposalPage({
...proposal,
token: token
});
cy.wait("@pi.summaries", { timeout: 500 });
cy.findByTestId("record-title").should("have.text", proposal.name);
});
});

it("Non-paid user can not create proposals", () => {
const user = {
email: "user3@example.com",
username: "user3",
password: "password"
};
cy.login(user);
it("should not be able to create proposals without fill the input", () => {
// paid user with proposal credits
cy.userEnvironment("user", { verifyIdentity: true });
cy.recordsMiddleware("new", {});
cy.visit("/record/new");
cy.findByRole("button", { name: /submit/i }).click();
cy.findByTestId("proposal-name").parent().find("p").contains("Required");
cy.findByTestId("proposal-amount").parent().find("p").contains("Required");
cy.get("[data-testid=datepicker]:eq(0)")
.find("p")
.contains("Please pick a start date");
cy.get("[data-testid=datepicker]:eq(1)")
.find("p")
.contains("Please pick an end date");
});

it("should not be able create proposals with non-paid user", () => {
cy.userEnvironment("unpaid", { verifyIdentity: true });
cy.visit("/");
cy.findByText(/new proposal/i).should("be.disabled");
const proposal = buildProposal();
cy.visit("/record/new");
cy.typeCreateProposal(proposal);
cy.findByText(
/you won't be able to submit comments or proposals before paying the paywall/i
).should("be.visible");
const proposal = buildProposal();
cy.findByTestId("proposal-name").should("be.visible").type(proposal.name);
cy.findByTestId("text-area").type(proposal.description);
cy.findByRole("button", { name: /submit/i }).should("be.disabled");
});
});
2 changes: 1 addition & 1 deletion teste2e/cypress/pki.js
Expand Up @@ -70,7 +70,7 @@ export const keysToHex = ({ publicKey, secretKey }) => ({
secretKey: toHex(secretKey)
});

const keysFromHex = ({ publicKey, secretKey }) => ({
export const keysFromHex = ({ publicKey, secretKey }) => ({
publicKey: toByteArray(publicKey),
secretKey: toByteArray(secretKey)
});
Expand Down
40 changes: 23 additions & 17 deletions teste2e/cypress/support/commands.js
Expand Up @@ -30,8 +30,12 @@ import * as pki from "../pki";
import get from "lodash/fp/get";
// TODO: consider moving general functions like makeProposal and signRegister
// to a more general lib file other than api.
import { makeProposal, signRegister } from "../utils";
import { shortRecordToken } from "../utils";
import {
makeProposal,
signRegister,
shortRecordToken,
RECORD_DOMAINS
} from "../utils";
import { middlewares as recordMiddlewares } from "./mock/records";
import { middlewares as ticketVoteMiddlewares } from "./mock/ticketvote";
import { middlewares as commentsMiddlewares } from "./mock/comments";
Expand Down Expand Up @@ -149,22 +153,24 @@ Cypress.Commands.add("approveProposal", ({ token }) =>
Cypress.Commands.add("typeCreateProposal", (proposal) => {
cy.server();
cy.findByTestId("proposal-name").type(proposal.name);
cy.findByTestId("text-area").type(proposal.description);
cy.findByTestId("proposal-amount").type(String(proposal.amount / 100));
// get dollars from cents.

const startDate = new Date(proposal.startDate * 1000);
cy.findAllByTestId("datepicker").first().children().first().click();
cy.findAllByTestId("days-list")
.first()
.findByText(startDate.getDate())
.click();
cy.findAllByTestId("datepicker").first().next().children().first().click();
cy.get("[data-testid=days-list]:eq(1)").find(">li").last().click();
const domainTxt = RECORD_DOMAINS[proposal.domain];
cy.get("#proposal-domain-selector")
.click()
.contains(domainTxt)
.click({ force: true });
cy.route("POST", "/api/records/v1/new").as("newProposal");
cy.findByRole("button", { name: /submit/i }).click();
// needs more time in general to complete this request so we increase the
// responseTimeout
cy.wait("@newProposal", { timeout: 10000 }).should((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.record)
.to.have.property("censorshiprecord")
.and.be.a("object")
.and.have.all.keys("token", "signature", "merkle");
cy.assertProposalPage({
...proposal,
token: xhr.response.body.record.censorshiprecord.token
});
});
cy.findByTestId("text-area").type(proposal.description);
});

Cypress.Commands.add("assertListLengthByTestId", (testid, expectedLength) =>
Expand Down
24 changes: 24 additions & 0 deletions teste2e/cypress/support/core/api.js
Expand Up @@ -102,7 +102,31 @@ export function detailsReply({
return { record };
}

/**
* newRecordReply is the reply to the new command. It returns a new record for the
* request data with given `files`, `publickey`, `signature` and `username` testParams.
*
* @param {Object} { testParams, requestParams }
* @returns Proposal
*/
export function newRecordReply({
testParams: { username },
requestParams: { files = [], publickey, signature }
}) {
const record = new Record({
status: 1,
state: 1,
version: 1,
files,
author: username,
publickey,
signature
});
return { record };
}

export const repliers = {
new: newRecordReply,
records: recordsReply,
inventory: inventoryReply,
policy: policyReply,
Expand Down
16 changes: 13 additions & 3 deletions teste2e/cypress/support/core/generate.js
Expand Up @@ -86,6 +86,12 @@ export function Record({
status: recordStatus,
state: recordState,
version: recordVersion,
publickey,
signature: recordSignature = faker.datatype.hexaDecimal(
128,
false,
/[0-9a-z]/
),
files = []
} = {}) {
const token = recordToken || Token();
Expand All @@ -106,15 +112,19 @@ export function Record({
signature,
merkle: faker.datatype.hexaDecimal(64, false, /[0-9a-z]/)
};
this.files = [new File(fileIndex), ...files.map((f) => new File(f))];
if (files.length == 2) {
this.files = files;
} else {
this.files = [new File(fileIndex), ...files.map((f) => new File(f))];
}
this.metadata = [
UserMetadata(user),
RecordMetadata({
token,
version,
status,
publickey: user.publickey,
signature,
publickey: publickey || user.publickey,
signature: recordSignature,
timestamp
})
];
Expand Down
20 changes: 15 additions & 5 deletions teste2e/cypress/support/users/api.js
@@ -1,6 +1,6 @@
import pick from "lodash/fp/pick";

import { PaymentCredits, User, userByType } from "./generate";
import { PaymentCredits, User, userByType, Identity } from "./generate";

export const API_BASE_URL = "/api/v1/user";

Expand All @@ -11,10 +11,15 @@ export const API_BASE_URL = "/api/v1/user";
* @returns User
*/
export function loginReply({
testParams: { userType, ...userProps },
testParams: { userType, verifyIdentity, ...userProps },
requestParams: { email }
}) {
return userByType(userType, { ...userProps, email });
const user = userByType(userType, { ...userProps, email });
if (verifyIdentity) {
const { userid, publickey } = user;
Identity({ userid, publickey });
}
return user;
}

/**
Expand All @@ -23,8 +28,13 @@ export function loginReply({
* @param {Object} { testParams }
* @returns User
*/
export function meReply({ testParams: { userType } }) {
return userByType(userType);
export function meReply({ testParams: { userType, verifyIdentity } }) {
const user = userByType(userType);
if (verifyIdentity) {
const { userid, publickey } = user;
Identity({ userid, publickey });
}
return user;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions teste2e/cypress/support/users/commands.js
Expand Up @@ -8,13 +8,13 @@ Cypress.Commands.add(
createMiddleware({ packageName: "user", repliers, baseUrl: API_BASE_URL })
);

Cypress.Commands.add("userEnvironment", (userType) => {
Cypress.Commands.add("userEnvironment", (userType, { verifyIdentity } = {}) => {
cy.wwwMiddleware(
"api",
{ isActive: userType !== "noLogin" },
{ headers: { "x-csrf-token": "abcdefghijklmnopqrstuvwxyz" } }
);
cy.userMiddleware("me", { userType });
cy.userMiddleware("me", { userType, verifyIdentity });
cy.userMiddleware("payments/registration", {
haspaid: userType !== "unpaid"
});
Expand Down
17 changes: 14 additions & 3 deletions teste2e/cypress/support/users/generate.js
Expand Up @@ -2,6 +2,7 @@ import faker from "faker";
import compose from "lodash/fp/compose";
import map from "lodash/fp/map";
import times from "lodash/fp/times";
import * as pki from "../../pki";

export function User({
isadmin = false,
Expand All @@ -22,7 +23,7 @@ export function User({
this.paywalladdress = paywalladdress || `Ts${faker.datatype.hexaDecimal(33)}`;
this.paywalltxid =
paywalltxid || faker.datatype.hexaDecimal(64, false, /[0-9a-z]/);
this.publickey = publickey || faker.datatype.hexaDecimal(64);
this.publickey = publickey || pki.toHex(faker.datatype.hexaDecimal(64));
this.paywallamount = 10000000;
this.paywalltxnotbefore = Date.now() / 1000 - 3600;
this.lastlogintime = faker.time.recent() / 1000;
Expand Down Expand Up @@ -60,13 +61,13 @@ export function userByType(userType, props) {
case "unpaid":
return UserUnpaid(props);
case "user":
return User(props);
return new User(props);
case "totp":
return UserTotp(props);
case "noLogin":
return {};
default:
return User(props);
return new User(props);
}
}

Expand All @@ -83,3 +84,13 @@ export function PaymentCredits({ spent = 0, unspent = 0 } = {}) {
this.spentcredits = makeCredits(spent);
this.unspentcredits = makeCredits(unspent);
}

export function Identity({ userid, publickey }) {
return pki.generateKeys().then((keys) => {
const stringKeys = {
secretKey: pki.toHex(keys.secretKey),
publicKey: publickey
};
pki.importKeys(userid, stringKeys);
});
}
21 changes: 21 additions & 0 deletions teste2e/cypress/utils.js
Expand Up @@ -48,6 +48,27 @@ export const PROPOSAL_SUMMARY_STATUS_CLOSED = "closed";
export const PROPOSAL_BILLING_STATUS_CLOSED = 2;
const PROPOSAL_STATE_UNVETTED = 1;
const PROPOSAL_STATE_VETTED = 2;
const monthLabels = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];

export const RECORD_DOMAINS = {
development: "Development",
marketing: "Marketing",
research: "Research",
design: "Design"
};

const findRecordFileByName = (record, name) =>
compose(
Expand Down

0 comments on commit 19e2970

Please sign in to comment.