Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
cypress-crud
Advanced tools
cy.crud is a project that aims to have a new framework to make cy.api and cy.request easier
NodeJS must be installed and Cypress must be version 10 or higher for this package to function correctly.
NodeJs
Cypress version 10 >
To install the package in your Cypress project, use the command
npm i cypress-crud
The CRUD was designed to automatically add dependencies and configurations to the e2e.js
file and the cypress.config.js
file, eliminating the need to manually include anything for the library's functionality.
e2e.js:
export {
crudStorage,
} from "cypress-crud/src/gherkin/bdd.js";
import "cypress-plugin-steps";
export const faker = require("generate-datafaker");
import "cypress-crud";
import "cypress-plugin-api";
import "cypress-mochawesome-reporter/register";
import spok from "cy-spok";
// export default spok;
// close json file in variable
import _ from "lodash";
export function clone(json) {
return _.cloneDeep(json);
}
cypress.config.js:
const { defineConfig } = require("cypress");
const fs = require("fs");
const path = require("path");
const readFixtures = require("./node_modules/cypress-crud/src/runAllJson");
module.exports = defineConfig({
reporter: "cypress-mochawesome-reporter",
e2e: {
defaultCommandTimeout: 180000,
pageLoadTimeout: 160000,
requestTimeout: 160000,
trashAssetsBeforeRuns: true,
testIsolation: false,
experimentalRunAllSpecs: true,
setupNodeEvents(on, config) {
// reporter: "cypress-mochawesome-reporter",
require("cypress-mochawesome-reporter/plugin")(on);
on("task", {
crudLog(message) {
console.log(message);
return null;
},
runFixtures({ folderPath }) {
const fixturesDir = path.join(
__dirname,
"./cypress/fixtures",
folderPath || ""
);
const files = readFixtures(fixturesDir);
const data = files.map((file) => ({
fileName: file.replace(fixturesDir + path.sep, ""),
content: JSON.parse(fs.readFileSync(file, "utf8")),
}));
return data;
},
});
// adjust to print size
on("before:browser:launch", (browser, launchOptions) => {
if (browser.family === "chromium" && browser.name !== "electron") {
launchOptions.args.push("--window-size=1500,1200");
}
if (browser.name === "electron") {
launchOptions.preferences.width = 1500;
launchOptions.preferences.height = 1200;
}
if (browser.family === "firefox") {
launchOptions.args.push("--width=1500");
launchOptions.args.push("--height=1200");
}
return launchOptions;
});
},
},
});
// CHANGE TITLE and SUBTITLE
// in cypress.env.json
// "title": "TESTING",
// "subTitle": "Project in Cypress"
cypress.env.json:
{
"environment": "QA",
"QA": {
"endpoint": "https://restcountries.com/v3.1/translation/germany",
"reqres": "https://reqres.in/api/users/2",
"location": "https://rickandmortyapi.com/api/location",
"serverest": "https://serverest.dev",
"getUser": "https://reqres.in/api/users/2",
"swagger": "https://api-desafio-qa.onrender.com/",
"crud_base": {
"crud_get_post": "swagger/crud",
"crud_getId_delete": "swagger/crud/{id}"
},
"endpoint_mercado": "swagger/mercado/{id}/produtos"
},
"PROD": {
"endpoint": "https://restcountries.com/v3.1/translation/germany",
"reqres": "https://reqres.in/api/users/2",
"location": "https://rickandmortyapi.com/api/location",
"serverest": "https://serverest.dev",
"getUser": "https://reqres.in/api/users/2",
"swagger": "https://api-desafio-qa.onrender.com/",
"crud_base": {
"crud_get_post": "swagger/crud",
"crud_getId_delete": "swagger/crud/{id}"
},
"endpoint_mercado": "swagger/mercado/{id}/produtos"
},
"DEV": {
"endpoint": "https://restcountries.com/v3.1/translation/germany",
"reqres": "https://reqres.in/api/users/2",
"location": "https://rickandmortyapi.com/api/location",
"serverest": "https://serverest.dev",
"getUser": "https://reqres.in/api/users/2",
"swagger": "https://api-desafio-qa.onrender.com/",
"crud_base": {
"crud_get_post": "swagger/crud",
"crud_getId_delete": "swagger/crud/{id}"
},
"endpoint_mercado": "swagger/mercado/{id}/produtos"
}
// "title": "TESTING",
// "subTitle": "Project in Cypress"
}
env_qa.js:
const { defineConfig } = require("cypress");
const config = require("./cypress.config");
const e2e = {
...config.e2e,
env: {
endpoint: "https://restcountries.com/v3.1/translation/germany",
reqres: "https://reqres.in/api/users/2",
swagger: "https://api-desafio-qa.onrender.com/",
location: "https://rickandmortyapi.com/api/location",
...config.env,
},
testIsolation: false, // in e2e:{}
experimentalRunAllSpecs: true, // in e2e:{}
chromeWebSecurity: false,
};
module.exports = defineConfig({
...config,
e2e,
});
// IN PACKAGE.JSON
// "scripts": {
// "cy:run:qa": "cypress run --config-file env_qa.js"
// },
package.json
// create new environment DEV env_dev.js, env_prod.js
"scripts": {
"cy:run:qa": "cypress run --config-file env_qa.js",
"cy:open:qa": "cypress open --config-file env_qa.js",
}
Use faker. options for generate data faker
{
"post": "swagger/login",
"body": {
"username": "admin",
"password": "password",
"name": "faker.name", // faker.nome
"email": "faker.email",
"enterprise": "faker.enterpriseName", // faker.empresaNome faker.entrerprise
"state": "faker.state", // faker.estado
"city": "faker.city", // faker.cidade
"country": "faker.country", //faker.pais
"street": "faker.street", // faker.endereco // faker.address // faker.rua
"phoneNumber": "faker.phoneNumber", // faker.numeroTelefone
"cep": "faker.cep",
"cpf": "faker.cpf",
"cnpj": "faker.cnpj",
"passwords": "faker.password", //faker.senha
"uuid": "faker.uuid",
"birthdate": "faker.birthdate", // faker.aniversario
"avatar": "faker.avatar",
"professional": "faker.professional", // faker.profissao
"product": "faker.product", // faker.produto
"imagem": "faker.image", // faker.imagem
"text": "faker.text", // faker.texto
"title": "faker.title", // faker.titulo
"actualDate": "faker.actualDate", // faker.dataAtual
"futureDate": "faker.futureDate", // faker.dataFutura
"fruta": "faker.fruta",
"fruit": "faker.fruit",
"object": "faker.object", // faker.objeto
"num": "faker.number(12)", // 123484218445
"number": "faker.number(7)", // 9713187
},
};
// result
{
"username": "admin",
"password": "password",
"test": "Jam Batista",
"email": "joaogabriel@hotmail.com",
"enterprise": "Ana Clara CloudNet",
"state": "Ceará",
"city": "Guatemala City",
"country": "Alemanha",
"street": "Alhambra, Granada, Spain",
"phoneNumber": "11995655467",
"cep": "69304525",
"cpf": "94344989023",
"cnpj": "02708629000116",
"passwords": "4)={[W.oHj",
"uuid": "0de2e006-8bfa-44cb-b05f-d3c019249a20",
"birthdate": "1952-06-15T02:41:02.520Z",
"avatar": "https://avatars.githubusercontent.com/u/36132952",
"num": "123484218445",
"number": "9713187"
}
it("Run all JSONs in folder", () => {
cy.runFixtures("examples"); // run all JSONs in folder
});
it("Run all JSONs", () => {
cy.runFixtures(); // run all JSONs in fixtures
});
en:
For your project setup, you need to create a JSON file inside the Fixtures
folder. This file can be placed directly in the folder or within a subfolder for better organization according to your project's needs.
br:
Para configurar o seu projeto, você precisa criar um arquivo JSON dentro da pasta Fixtures
. Este arquivo pode ser colocado diretamente na pasta ou dentro de uma subpasta para melhor organização de acordo com a necessidade do seu projeto.
Example path:
Fixtures/Token/createToken.json
JSON
:br:
Aqui temos algumas formas de usar o GET, que pode ser diretamente com a url preterida, ou com o nome da key criada no env (cypress.env.json) swagger (ou qualquer outro nome), e também você pode usar a continuação da sua url.
en:
Here we have some ways to use GET, which can be directly with the deprecated url, or with the name of the key created in the env (cypress.env.json) swagger (or any other name), and you can also use the continuation of your url.{
"get": "https://reqres.in/api/users/2",
}
{
"get": "swagger", // show in cypress.env.json
}
{
"get": "swagger/login", // result: https://api-desafio-qa.onrender.com/login
}
br:
Abaixo, um JSON efetuando uma request com a path text
que servirá para documentar a ação do JSON.
en:
Below, a JSON making a request with path text
that will serve to document the JSON action.{
"text": "efetaundo request Mockable.io",
"get": "http://demo7018197.mockable.io/"
}
br:
Para executar diferentes jsons em diferentes ambientes na mesma execução.
en:
To run different jsons in different environments in the same run.
it("request", () => {
cy.crud({ get: "crud_get_post", env: "PROD" });
cy.crud({ get: "crud_get_post", env: "DEV" });
});
image
br:
Efetuando request e salvando o email do retorno da requisição. Conforme imagem, imagem foi salva na variável email. (crudStorage.save.email).
Caso, seja necessário salvar essa variável com outro nome, basta usar da forma 2 ou 3.
Exemplo 4 antes de salvar verificamos se o valor é igual.
en:
Making a request and saving the request return email. As shown in the image, the image was saved in the email variable. (crudStorage.save.email).
If it is necessary to save this variable with another name, just use form 2 or 3.
Example 4, before saving, we check if the value is the same.
// 1
{
"text": "efetaundo request Reqres.in",
"get": "https://reqres.in/api/users/2",
"save": "email"
}
// 2
{
"text": "efetaundo request Reqres.in",
"get": "https://reqres.in/api/users/2",
"save": "email ::: user_email"
}
// 3
{
"text": "efetaundo request Reqres.in",
"get": "https://reqres.in/api/users/2",
"save": {"path":"email", "as": "user_email"}
}
// 4
{
"text": "salvando com variável email e alias",
"get": "https://reqres.in/api/users/2",
"save": {
"path": "email",
"eq": "janet.weaver@reqres.in",
"as": "user_email"
}
}
{
"text": "salvando com variável email e alias",
"get": "https://reqres.in/api/users/2",
"save": [{
"path": "email",
"eq": "janet.weaver@reqres.in",
"as": "user_email"
},
{
"path": "id",
}
]
}
save email 1
save whit alias 2
save whit path and as 3
save whit path eq and as 4
// request
{
"text": "Expect validação do tipo de retorno string number boolean ...",
"get": "https://reqres.in/api/users/2",
"body": {
"name": "Jhon"
},
"saveRequest": "name"
}
// saved name
{
"get": "https://reqres.in/api/users/2",
"body": {
"name": "{request_name}"
}
// result Jhon
}
{
"text": "Expect validação do tipo de retorno string number boolean ...",
"get": "https://reqres.in/api/users/2",
"expect": {
"path": "first_name",
"as": "name"
}
}
[
{
"text": "salvando para usar em outra request",
"get": "https://reqres.in/api/users/2",
"expect": {
"path": "first_name",
"as": "name"
}
},
{
"text": "usando valor salvo",
"post": "https://reqres.in/api/users/2",
"body": {
"name": "{name}"
},
"expect": "name"
}
]
Result
Rescue save valur in url
{
"text": "save id",
"get": "https://reqres.in/api/users/2",
"save": "id"
}
// in new json rescue id
{
"text": "rescue id and use in url",
"get": "https://reqres.in/api/users/{id}"
}
Second way of use
import { faker, clone, crudStorage } from "../support/e2e";
describe("", () => {
afterEach(() => {
cy.crudScreenshot();
});
it("request show json", () => {
console.log(crudStorage.save.name); // result Janet
});
});
br:
Expect irá nos ajudar nas validações das keys, veremos exemplos:
en:
Expect will help us with key validations, we will see examples:
{
"text": "usando expect",
"get": "https://reqres.in/api/users/2",
"expect": "first_name"
}
br:
Usando === você usará o equal para validar
en:
Using === you will use equal to validate
// 1
{
"text": "usando expect com === para validar",
"get": "https://reqres.in/api/users/2",
"expect": "first_name === Janet"
}
// 2
{
"text": "usando expect com === para validar",
"get": "https://reqres.in/api/users/2",
"expect": {"path":"first_name", "eq": "Janet"}
}
br:
Usando ::: você usará o salvar o valor da key
en:
Using ::: you will use save the key value
// 1
{
"text": "usando expect com ::: para salvar o valor da key",
"get": "https://reqres.in/api/users/2",
"expect": "first_name ::: name"
}
// 2
{
"text": "usando expect com ::: para validar",
"get": "https://reqres.in/api/users/2",
"expect": {"path":"first_name", "as": "name"}
}
// 3
{
"text": "usando expect com ::: para salvar o valor da key",
"get": "https://reqres.in/api/users/2",
"expect": { "path": "first_name", "eq": "Janet", "as": "name" }
}
{
// save name in position 4
"expect": "name:::>4"
}
{
// save name whit alias user_name in position 4
"expect": "name:::user_name>4"
}
{
// eq name Micheal save alias user
"expect": "name===Michael:::user"
}
expect eq and as
br:
Usando o position você consegue validar numa lista de array a posição informada.
en:
Using position you can validate the entered position in an array list.
Return image
{
"text": "Expect validação por array",
"get": "https://reqres.in/api/users",
"expect": { "path": "first_name", "position": 2 }
}
Result image
save position
{
"text": "Expect validação por array",
"get": "https://reqres.in/api/users",
"expect": { "path": "first_name", "position": 2, "as": "name" }
}
br:
Adicionando type ao seu json, você irá validar qual o tipo o dado retornado
en:
By adding type to your json, you will validate the type of data returned.
{
"text": "Expect validação do tipo de retorno string number boolean ...",
"get": "https://reqres.in/api/users/2",
"expect": {
"path": "first_name",
"type": "string"
}
}
Return
br:
Usando ||
você consegue validar a possibilidade de vários valores, ideal para quando o retorno pode ser de valores diferentes.
en:
Using ||
you can validate the possibility of multiple values, ideal for when the return may be different values.
{
"text": "Equal validando possibilidade de vários valores",
"get": "https://reqres.in/api/users/2",
"expect": {
"path": "first_name",
"eq": "Jam || Batista || test || Janet"
}
}
br:
O condiction está relacionado a request anterior, caso o condition seja condition-accept o cypress-crud
passará para o JSON seguinte.
en:
The condition is related to the previous request, if the condition is condition-accept, cypress-crud
will pass to the next JSON.
{
"text": "post create new user",
"get": "swagger/users"
} // return 200
{ // if return previous request name not null
"condition": { "path": "name" },
"get": "swagger/users",
}
{ // if return previous request status 200
"condition": 200,
"get": "swagger/users",
}
{ // if return previous request name
"condition": "name",
"get": "swagger/users",
}
{
// if return previous request name eq Jam
"condition": { "path": "name", "eq": "Jam" },
"get": "swagger/users"
}
br:
Para usar o cy.crud é simples, basta colocar os jsons na pasta fixtures
ou subpastas da fixtures
abaixo formas de uso:
en:
To use cy.crud, it's simple, just place the jsons in the fixtures
folder or subfolders of fixtures
below:
it("request show json", () => {
cy.crud("examples/big_data");
});
it("request show json", () => {
cy.crud("big_data");
});
Use for object
let json = { get: "http..." };
it("request show json", () => {
cy.crud(json);
});
it("request show json", () => {
cy.crud({ get: "http...." });
});
cy.crud({ get: "http...." }).expect({ path: "first_name" });
cy.crud({ get: "http...." }).save({ path: "first_name" });
br:
Com o cy.crud você consegue em apenas um it
rodas todos os jsons que estão na pasta fixtures
ou subpastas.
en:
With cy.crud you can in just one it
run all the jsons that are in the fixtures
folder or subfolders.
it("RUN all jsons in path fixtures", () => {
cy.runFixtures();
});
Run all jsons in path
it("RUN all jsons in path fixtures", () => {
cy.runFixtures("crud");
});
br:
A função schema
. Ele garante que a resposta de uma solicitação atenda aos critérios especificados em um esquema JSON específico. Essa validação ajuda a confirmar se a estrutura e os dados retornados estão alinhados com as expectativas definidas no teste.
en:
The schema
function. It ensures that a request's response meets criteria specified in a specific JSON schema. This validation helps confirm that the structure and data returned align with the expectations defined in the test.
{
"text": "validando schema",
"get": "https://reqres.in/api/users/2",
"schema": "crud_users"
}
cy.crud("json");
cy.crud({ payload: "examples/json" }).schema({schema: "crud_users",});
{
"get": "local/approval",
"schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"items": [
{
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"cpf": {
"type": "string"
},
"status": {
"type": "string"
}
},
"required": ["id", "name", "email", "cpf", "status"]
},
{
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"cpf": {
"type": "string"
},
"status": {
"type": "string"
}
},
"required": ["id", "name", "email", "cpf", "status"]
}
]
}
}
A snippet has been created to streamline the test construction process.
cy.crud();
.save({path:''})
.expects({path:''})
.schema({schema:''})
This function is used to write data to a JSON file in the Cypress fixtures directory. It creates a JSON file with the provided data from the specified request response. This is useful for generating simulated response files for testing purposes.
cy.crud( "token/createToken.json").write({ path: "user/getUser" });
explanation:
create json response in cypress/fixtures/user
This function is used to read data from a JSON file in the Cypress fixtures directory. It reads the content of the specified JSON file and makes it available for use in the test
cy.crud( "token/createToken.json" ).read({ path: "user/getUser" });
cy.read({ path: "user/getUser" }).then((json) => {
console.log(json);
});
explanation:
read json response in cypress/fixtures/user
Include tags in your
package.json
to only execute jsons that have this tag, or tags. No other JSON will be executed iftag
is active inpackage.json
.
EX:
{
"name": "testcrud201024",
"tag": "crud",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "cypress open",
"exe": "cypress run"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cypress": "^13.15.1",
"cypress-crud": "^4.1.6"
}
}
cy.crud({
text: "tag crud",
get: "http://localhost:3000/users",
tag: "crud",
});
or
{
"name": "testcrud201024",
"tag": "pay, crud",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "cypress open",
"exe": "cypress run"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cypress": "^13.15.1",
"cypress-crud": "^4.1.6"
}
}
// tags crud and pay runner
describe("Test com tag", () => {
it("executando json com tag", () => {
cy.crud({
text: "tag crud",
get: "http://localhost:3000/users",
tag: "crud",
});
cy.crud({
text: "tag pay",
get: "http://localhost:3000/users",
tag: "pay",
});
cy.crud({
text: "tag pay",
get: "http://localhost:3000/users",
tag: "pall",
});
});
});
For requests that require a mock, simply specify the mock
variable and provide the path to where the mock is stored.
Example:
The file can be found in fixtures in the mocks folder, called json_mock.
{
"get": "https://demo0065046.mockable.io/", // or get: true // post: true // delete": true // path: true
"mock": "mocks/json_mock"
}
Mock construction:
{
"response": {
"status": 200,
"body": { "authorization": "Bearer" }
}
}
In this example, the body
field directs to the mock file located in the mocks
folder, which contains the predefined structure of the fields to be returned in the response.
Validate mock:
To validate the mock, you can simply include the checks in the JSON file itself or embed them in the test file.
JSON fixtures
{
"get": "https://demo0065046.mockable.io/", // or get: true // post: true // delete": true // path: true
"mock": "mocks/json_mock"
}
// in cypress.env.json
"hideReport": ["body", "headers"]
// result
{
"get": "https://reqres.in/api/users/2",
"failOnStatusCode": false,
"body": "hide active in path",
"headers": "hide active in path"
}
br:
sempre que você efetua uma requisição, a url é salva em crudStora.save.url, então na próxima requisição você pode usar como a abaixo:
en:
whenever you make a request, the url is saved in crudStora.save.url, so in the next request you can use it like the one below:
{
"text": "GET list in projects",
"get": "swagger/projects", // https://api-desafio-qa.onrender.com/projects
},
{
"text": "Post in projects using data fakers",
"body": {
"name": "faker.enterprise",
"leader": "faker.name",
"description": "faker.text",
"endDate": "2024-08-08",
},
"post": "{url}", // https://api-desafio-qa.onrender.com/projects
}
describe(`Test cypress-crud Property search`, () => {
let data;
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiIxMjM0NTY3ODkwIiwicGFzc3dvcmQiOiJKb2huIERvZSJ9.d7gibg6eK9oxrpcCob-MuNz65NHMWNK1x4otVLyHPCo";
before(function () {
cy.crudSafeData(token).then((safe) => {
crudStorage.save.email_login = safe.key;
crudStorage.save.password_login = safe.password;
});
});
it("Decode", () => {
console.log(crudStorage.save);
});
});
OUR
IN CYPRESS.ENV.JSON
"dataSafe": "token jwt",
"hideCredentials": true,
"hideCredentialsOptions": { "body": ["email", "password"] } // change for your paths
COMPLETE ENV
env: {
hideCredentials: true,
hideCredentialsOptions: {
headers: ['authorization'],
auth: ['pass'],
body: ['username'],
query: ['password']
}
}
OUR
CYPRESS.CONFIG.JS
env:{
"dataSafe": "your token jwt",
"hideCredentials": true,
"hideCredentialsOptions": { "body": ["email", "password"] } // change for your paths
}
COMPLETE ENV
env: {
hideCredentials: true,
hideCredentialsOptions: {
headers: ['authorization'],
auth: ['pass'],
body: ['username'],
query: ['password']
}
}
crudStorage
crudStorage.alias
crudStorage.alias.bodyResponse
crudStorage.save
crudStorage
crudStorage.save.url
crudStorage.save.beforeUrl
crudStorage.request
it("crud run", () => {
cy.crud("example").then(() => {
expect(crudStorage.save.nome).not.empty;
});
});
// response
[
{
"address": "Av. Paulista, 1000",
"city": "São Paulo",
"cnpj": "12345678901234",
"employees": [
{
"email": "maria.silva@techinnovations.com.br",
"employeeId": 1,
"name": "Maria Silva",
"position": "Gerente de Projetos"
}
],
"id": 1,
"name": "Tech Innovations Ltda",
"products": [
{
"price": 5000,
"productDescription": "Software completo para gestão empresarial, incluindo módulos de finanças, vendas e operações.",
"productId": 1,
"productName": "Software de Gestão"
}
]
}
]
it("Company crud", () => {
cy.crud({ get: "swagger/company" }).then(() => {
cy.findInJson("city").should("deep.equal", ["São Paulo"]);
cy.findInJson("productId").should("deep.equal", [1]);
});
});
1
2
3
4
5
6
7
8
9
10
11
12
13
This project is the collaborative effort of Jameson Batista and Gabriel Lopes. We are proud to share our work with the community and hope it can inspire and assist other developers.
For tips, inquiries, or just to connect, follow us on LinkedIn:
FAQs
cy.crud is a project that aims to have a new framework to make cy.api and cy.request easier
We found that cypress-crud demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.