Basic outfit state Cypress tests
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"baseUrl": "http://localhost:3000"
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"ignoreTestFiles": ["**/__snapshots__/*", "**/__image_snapshots__/*"]
|
||||
}
|
||||
|
|
109
cypress/integration/WardrobePage/Basic outfit state.spec.js
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Give network requests a bit of breathing room!
|
||||
const networkTimeout = { timeout: 12000 };
|
||||
|
||||
describe("WardrobePage: Basic outfit state", () => {
|
||||
it("Initialize simple outfit from URL", () => {
|
||||
cy.visit("/outfits/new?species=1&color=8&objects[]=76789");
|
||||
|
||||
getSpeciesSelect(networkTimeout)
|
||||
.find(":selected")
|
||||
.should("have.text", "Acara");
|
||||
getColorSelect().find(":selected").should("have.text", "Blue");
|
||||
cy.location().toMatchSnapshot();
|
||||
|
||||
cy.contains("A Warm Winters Night Background", networkTimeout).should(
|
||||
"exist"
|
||||
);
|
||||
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
});
|
||||
|
||||
it("Changes species and color", () => {
|
||||
cy.visit("/outfits/new?species=1&color=8&objects[]=76789");
|
||||
|
||||
getSpeciesSelect(networkTimeout)
|
||||
.find(":selected")
|
||||
.should("have.text", "Acara");
|
||||
getColorSelect().find(":selected").should("have.text", "Blue");
|
||||
cy.location().toMatchSnapshot();
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
|
||||
getSpeciesSelect().select("Aisha");
|
||||
|
||||
getSpeciesSelect().find(":selected").should("have.text", "Aisha");
|
||||
getColorSelect().find(":selected").should("have.text", "Blue");
|
||||
cy.location().toMatchSnapshot();
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
|
||||
getColorSelect().select("Red");
|
||||
|
||||
getSpeciesSelect().find(":selected").should("have.text", "Aisha");
|
||||
getColorSelect().find(":selected").should("have.text", "Red");
|
||||
cy.location().toMatchSnapshot();
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
});
|
||||
|
||||
it.only("Changes pose", () => {
|
||||
cy.visit("/outfits/new?species=1&color=8&pose=HAPPY_FEM");
|
||||
|
||||
getPosePickerButton(networkTimeout).click();
|
||||
getPosePickerOption("Happy and Feminine").should("be.checked");
|
||||
cy.location().toMatchSnapshot();
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
|
||||
getPosePickerOption("Sad and Masculine").check({ force: true });
|
||||
getPosePickerOption("Sad and Masculine").should("be.checked");
|
||||
cy.location().toMatchSnapshot();
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
});
|
||||
|
||||
it("Toggles item", () => {
|
||||
cy.visit("/outfits/new?species=1&color=8&objects[]=76789");
|
||||
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
cy.location().toMatchSnapshot();
|
||||
|
||||
cy.contains("A Warm Winters Night Background").click();
|
||||
|
||||
getOutfitPreview().toMatchImageSnapshot();
|
||||
cy.location().toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("Renames outfit", () => {
|
||||
cy.visit("/outfits/new?name=My+outfit&species=1&color=8");
|
||||
|
||||
getOutfitName(networkTimeout).should("have.text", "My outfit");
|
||||
|
||||
getOutfitName().click().type("Awesome outfit{enter}");
|
||||
|
||||
getOutfitName().should("have.text", "Awesome outfit");
|
||||
cy.location().toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
function getSpeciesSelect(options) {
|
||||
return cy.get("[data-test-id=wardrobe-species-picker]", options);
|
||||
}
|
||||
|
||||
function getColorSelect(options) {
|
||||
return cy.get("[data-test-id=wardrobe-color-picker]", options);
|
||||
}
|
||||
|
||||
function getPosePickerButton(options) {
|
||||
return cy.get("[data-test-id=wardrobe-pose-picker]", options);
|
||||
}
|
||||
|
||||
function getPosePickerOption(label, options) {
|
||||
return cy.get(`input[aria-label="${CSS.escape(label)}"]`, options);
|
||||
}
|
||||
|
||||
function getOutfitPreview() {
|
||||
return cy.get("[data-test-id=wardrobe-outfit-preview]:not([data-loading])", {
|
||||
// A bit of an extra-long timeout, to await both server data and image data
|
||||
timeout: 15000,
|
||||
});
|
||||
}
|
||||
|
||||
function getOutfitName(options) {
|
||||
return cy.get("[data-test-id=outfit-name]", options);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Give network requests a bit of breathing room!
|
||||
const networkTimeout = { timeout: 6000 };
|
||||
const networkTimeout = { timeout: 10000 };
|
||||
|
||||
describe("WardrobePage: SearchPanel", () => {
|
||||
// NOTE: This test depends on specific search results on certain pages, and
|
||||
// could break if a lot of matching items are added to the site!
|
||||
it.only("Searches by keyword", () => {
|
||||
it("Searches by keyword", () => {
|
||||
cy.visit("/outfits/new");
|
||||
|
||||
// The first page should contain this item.
|
||||
|
|
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 288 KiB |
After Width: | Height: | Size: 284 KiB |
After Width: | Height: | Size: 280 KiB |
After Width: | Height: | Size: 288 KiB |
After Width: | Height: | Size: 288 KiB |
After Width: | Height: | Size: 51 KiB |
|
@ -0,0 +1,127 @@
|
|||
exports[`WardrobePage: Basic outfit state > Initialize simple outfit from URL #0`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=1&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=1&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"superDomain": "localhost"
|
||||
};
|
||||
|
||||
exports[`WardrobePage: Basic outfit state > Changes species and color #0`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=1&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=1&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"superDomain": "localhost"
|
||||
};
|
||||
|
||||
exports[`WardrobePage: Basic outfit state > Changes species and color #1`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=2&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=2&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"superDomain": "localhost"
|
||||
};
|
||||
|
||||
exports[`WardrobePage: Basic outfit state > Changes species and color #2`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=2&color=61&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=2&color=61&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"superDomain": "localhost"
|
||||
};
|
||||
|
||||
exports[`WardrobePage: Basic outfit state > Toggles item #0`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=1&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=1&color=8&pose=HAPPY_FEM&objects%5B%5D=76789",
|
||||
"superDomain": "localhost"
|
||||
};
|
||||
|
||||
exports[`WardrobePage: Basic outfit state > Toggles item #1`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=1&color=8&pose=HAPPY_FEM&closet%5B%5D=76789",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=1&color=8&pose=HAPPY_FEM&closet%5B%5D=76789",
|
||||
"superDomain": "localhost"
|
||||
};
|
||||
|
||||
exports[`WardrobePage: Basic outfit state > Changes pose #0`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=1&color=8&pose=HAPPY_FEM",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=1&color=8&pose=HAPPY_FEM",
|
||||
"superDomain": "localhost"
|
||||
};
|
||||
|
||||
exports[`WardrobePage: Basic outfit state > Changes pose #1`] =
|
||||
{
|
||||
"auth": "",
|
||||
"hash": "",
|
||||
"host": "localhost:3000",
|
||||
"hostname": "localhost",
|
||||
"href": "http://localhost:3000/outfits/new?name=&species=1&color=8&pose=SAD_MASC",
|
||||
"origin": "http://localhost:3000",
|
||||
"originPolicy": "http://localhost:3000",
|
||||
"pathname": "/outfits/new",
|
||||
"port": "3000",
|
||||
"protocol": "http:",
|
||||
"search": "?name=&species=1&color=8&pose=SAD_MASC",
|
||||
"superDomain": "localhost"
|
||||
};
|
|
@ -1,21 +1,6 @@
|
|||
/// <reference types="cypress" />
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
const { initPlugin } = require("cypress-plugin-snapshots/plugin");
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
}
|
||||
initPlugin(on, config);
|
||||
return config;
|
||||
};
|
||||
|
|
|
@ -1,25 +1 @@
|
|||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
import "cypress-plugin-snapshots/commands";
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
"apollo-server-testing": "^2.12.0",
|
||||
"auth0": "^2.28.0",
|
||||
"cypress": "^6.4.0",
|
||||
"cypress-plugin-snapshots": "^1.4.4",
|
||||
"dotenv-cli": "^3.1.0",
|
||||
"es6-promise-pool": "^2.5.0",
|
||||
"inquirer": "^7.3.3",
|
||||
|
|
|
@ -271,7 +271,7 @@ function OutfitHeading({ outfitState, dispatchToOutfit }) {
|
|||
<Box>
|
||||
<Box role="group" d="inline-block" position="relative" width="100%">
|
||||
<Heading1>
|
||||
<EditablePreview lineHeight="48px" />
|
||||
<EditablePreview lineHeight="48px" data-test-id="outfit-name" />
|
||||
<EditableInput lineHeight="48px" />
|
||||
</Heading1>
|
||||
</Box>
|
||||
|
|
|
@ -197,6 +197,12 @@ function OutfitControls({
|
|||
idealPose={outfitState.pose}
|
||||
onChange={onSpeciesColorChange}
|
||||
stateMustAlwaysBeValid
|
||||
speciesPickerProps={{
|
||||
"data-test-id": "wardrobe-species-picker",
|
||||
}}
|
||||
colorPickerProps={{
|
||||
"data-test-id": "wardrobe-color-picker",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</DarkMode>
|
||||
|
@ -210,6 +216,7 @@ function OutfitControls({
|
|||
dispatchToOutfit={dispatchToOutfit}
|
||||
onLockFocus={onLockFocus}
|
||||
onUnlockFocus={onUnlockFocus}
|
||||
data-test-id="wardrobe-pose-picker"
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
|
|
@ -63,6 +63,7 @@ function PosePicker({
|
|||
dispatchToOutfit,
|
||||
onLockFocus,
|
||||
onUnlockFocus,
|
||||
...props
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
const initialFocusRef = React.useRef();
|
||||
|
@ -193,6 +194,7 @@ function PosePicker({
|
|||
`,
|
||||
isOpen && "is-open"
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<EmojiImage src={getIcon(pose)} alt="Choose a pose" />
|
||||
</Button>
|
||||
|
|
|
@ -30,6 +30,7 @@ function WardrobePreviewAndControls({
|
|||
wornItemIds: outfitState.wornItemIds,
|
||||
onChangeHasAnimations: setHasAnimations,
|
||||
backdrop: <OutfitThumbnailIfCached outfitId={outfitState.id} />,
|
||||
"data-test-id": "wardrobe-outfit-preview",
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
@ -52,6 +52,7 @@ export function useOutfitPreview({
|
|||
loadingDelayMs,
|
||||
spinnerVariant,
|
||||
onChangeHasAnimations = null,
|
||||
...props
|
||||
}) {
|
||||
const appearance = useOutfitAppearance({
|
||||
speciesId,
|
||||
|
@ -102,6 +103,7 @@ export function useOutfitPreview({
|
|||
onChangeHasAnimations={onChangeHasAnimations}
|
||||
doTransitions
|
||||
isPaused={isPaused}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -122,6 +124,7 @@ export function OutfitLayers({
|
|||
spinnerVariant = "overlay",
|
||||
doTransitions = false,
|
||||
isPaused = true,
|
||||
...props
|
||||
}) {
|
||||
const containerRef = React.useRef(null);
|
||||
const [canvasSize, setCanvasSize] = React.useState(0);
|
||||
|
@ -178,6 +181,8 @@ export function OutfitLayers({
|
|||
// Create a stacking context, so the z-indexed layers don't escape!
|
||||
zIndex="0"
|
||||
ref={containerRef}
|
||||
data-loading={loading ? true : undefined}
|
||||
{...props}
|
||||
>
|
||||
{backdrop && (
|
||||
<FullScreenCenter>
|
||||
|
|
|
@ -27,6 +27,8 @@ function SpeciesColorPicker({
|
|||
isDisabled = false,
|
||||
speciesIsDisabled = false,
|
||||
size = "md",
|
||||
speciesPickerProps = {},
|
||||
colorPickerProps = {},
|
||||
onChange,
|
||||
}) {
|
||||
const { loading: loadingMeta, error: errorMeta, data: meta } = useQuery(gql`
|
||||
|
@ -188,6 +190,7 @@ function SpeciesColorPicker({
|
|||
valids={valids}
|
||||
speciesId={speciesId}
|
||||
colorId={colorId}
|
||||
{...colorPickerProps}
|
||||
>
|
||||
{
|
||||
// If the selected color isn't in the set we have here, show the
|
||||
|
@ -231,6 +234,7 @@ function SpeciesColorPicker({
|
|||
valids={valids}
|
||||
speciesId={speciesId}
|
||||
colorId={colorId}
|
||||
{...speciesPickerProps}
|
||||
>
|
||||
{
|
||||
// If the selected species isn't in the set we have here, show the
|
||||
|
|