laracasts / cypress

Laravel Cypress Integration
MIT License
617 stars 67 forks source link

Testing with Sail #26

Open underthecocotree opened 3 years ago

underthecocotree commented 3 years ago

Hey @JeffreyWay,

Another great package, thanks.

I just wanted to share my journey into getting to work this with Laravel Sail. We can add this to the Readme.md, adding configurations during the scaffold might be a bit of an overkill.

Follow the Installation and Environment Handling sections in Readme.md

Edit: cypress/support/index.js to stop the swapping of the .env files

before(() => {
    // cy.task('activateCypressEnvFile', {}, { log: false });
    // cy.artisan('config:clear', {}, { log: false });

    cy.refreshRoutes();
});

after(() => {
    // cy.task('activateLocalEnvFile', {}, { log: false });
    // cy.artisan('config:clear', {}, { log: false });
});

Run sail using .env.cypress

sail --env-file .env.cypress up


If you want to run tests on a separate database follow the rest of this guide.


Create a separate database

Sail does not provide sqlite, there might be a way to install it and configure it but I didn't find anything.

Credit to: https://michaelheap.com/laravel-sail-test-database/

Edit .env.cypress

DB_CONNECTION=mysql
DB_HOST=mysql_test
DB_DATABASE=
DB_USERNAME=root

Edit docker-compose.yml to create a new database

services:
   mysql_test:
        image: "mysql:8.0"
        environment:
            MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
            MYSQL_DATABASE: "${DB_DATABASE}"
            MYSQL_USER: "${DB_USERNAME}"
            MYSQL_PASSWORD: "${DB_PASSWORD}"
            MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
        networks:
            - sail
robsontenorio commented 3 years ago

@underthecocotree why stopping swap envs?

underthecocotree commented 3 years ago

From memory, I think sail caches the environment variables on load/boot. That is where ‘sail —env-file .env.cypress’ comes in handy

Thinking about it I guess it wouldn’t hurt to keep it. It’s been a while since I changed any of that code.

Have you been successful with testing with the code present?

matthewknill commented 2 years ago

I'm a bit confused how to get this working with docker. I added the following to my docker-compose.yml:

    ui:
        image: cypress/base:latest

It downloads the image but it doesn't seem to start correctly.

When I run sail npm install cypress --save-dev && sail npx cypress open I get the following:

No version of Cypress is installed in: /home/sail/.cache/Cypress/10.1.0/Cypress

Please reinstall Cypress by running: cypress install

----------

Cypress executable not found at: /home/sail/.cache/Cypress/10.1.0/Cypress/Cypress

----------

Platform: linux-x64 (Ubuntu - 21.10)
Cypress Version: 10.1.0

And after running composer require laracasts/cypress --dev, I'm unable to publish the boilerplate code with sail artisan cypress:boilerplate:

Cypress not found. Please install it through npm and try again.

npm install cypress --save-dev && npx cypress open

Since I can't publish the boilerplate code, I'm unable to get the .env.cypress file so it can be started with sail --env-file .env.cypress up.

Any help would be much appreciated...

parapente commented 2 years ago

I am leaving this here in case someone is trying to run cypress in a separate container with laravel sail. The changes below will also add novnc in a separate container that will be used to show the cypress desktop app so that you don't have to make any config changes to your system or install an X11 server.

Add the following services in docker-compose.yml:

  cypress:
    build:
      context: ./docker/cypress
      args:
        WWWUSER: "${WWWUSER}"
        WWWGROUP: "${WWWGROUP}"

    depends_on:
      - laravel.test
      - novnc
    environment:
      - CYPRESS_baseUrl=http://laravel.test:${APP_PORT:-80}
      - DISPLAY=novnc:0.0
    working_dir: /e2e
    entrypoint: cypress open --project /e2e
    volumes:
      - ./:/e2e
    networks:
      - sail

  novnc:
    build:
      context: ./docker/novnc
      dockerfile: Dockerfile
      args:
        WWWUSER: "${WWWUSER}"
        WWWGROUP: "${WWWGROUP}"
    ports:
      - "8080:8080"
    networks:
      - sail

Create the following folders:

ARG WWWGROUP ARG WWWUSER

RUN groupadd -o -g ${WWWGROUP} sail

do not log creating new user, otherwise there could be a lot of messages

RUN useradd -r --no-log-init -o -u ${WWWUSER} -g sail sail RUN install -d -m 0755 -o sail -g sail /home/sail

move test runner binary folder to the non-root's user home directory

RUN mv /root/.cache /home/sail/.cache

USER sail

show user effective id and group - it should be non-zero

meaning the current user "node" is not root

RUN id

ENV CYPRESS_CACHE_FOLDER=/home/sail/.cache/Cypress


Add docker\novnc\Dockerfile:

FROM alpine:3.16

ARG WWWGROUP ARG WWWUSER

Setup demo environment variables

ENV LANG=en_US.UTF-8 \ LANGUAGE=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 \ DISPLAY=:0.0

RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories RUN apk update && \ apk add \ novnc@testing \ bash \ fluxbox \ terminus-font \ supervisor \ tigervnc

RUN ln -s /usr/share/novnc/vnc.html /usr/share/novnc/index.html

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 8080

RUN addgroup -g ${WWWGROUP} sail

do not log creating new user, otherwise there could be a lot of messages

RUN adduser --disabled-password --gecos "" --uid ${WWWUSER} --ingroup sail sail RUN install -d -m 0755 -o sail -g sail /home/sail

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]


And finally add docker\novnc\supervisord.conf:

[supervisord] user=sail nodaemon=true logfile=/home/sail/supervisord.log pidfile=/home/sail/supervisord.pid

[program:xvnc] user=sail command=/usr/bin/Xvnc -SecurityTypes=None -localhost=0 :0.0 -listen tcp -ac autorestart=true

[program:novnc] user=sail command=/usr/bin/novnc_server --vnc localhost:5900 --listen 8080 autorestart=true

[program:fluxbox] user=sail command=fluxbox autorestart=true environment=HOME="/home/sail"

matthewknill commented 1 year ago

I am leaving this here in case someone is trying to run cypress in a separate container with laravel sail. The changes above will also add novnc in a separate container that will be used to show the cypress desktop app so that you don't have to make any config changes to your system or install an X11 server.

Add the following services in docker-compose.yml:

  cypress:
    build:
      context: ./docker/cypress
      args:
        WWWUSER: "${WWWUSER}"
        WWWGROUP: "${WWWGROUP}"

    depends_on:
      - laravel.test
      - novnc
    environment:
      - CYPRESS_baseUrl=http://laravel.test:${APP_PORT:-80}
      - DISPLAY=novnc:0.0
    working_dir: /e2e
    entrypoint: cypress open --project /e2e
    volumes:
      - ./:/e2e
    networks:
      - sail

  novnc:
    build:
      context: ./docker/novnc
      dockerfile: Dockerfile
      args:
        WWWUSER: "${WWWUSER}"
        WWWGROUP: "${WWWGROUP}"
    ports:
      - "8080:8080"
    networks:
      - sail

Create the following folders:

  • docker\cypress
  • docker\novnc Add docker\cypress\Dockerfile:
FROM cypress/included:9.7.0

ARG WWWGROUP
ARG WWWUSER

RUN groupadd -o -g ${WWWGROUP} sail
# do not log creating new user, otherwise there could be a lot of messages
RUN useradd -r --no-log-init -o -u ${WWWUSER} -g sail sail
RUN install -d -m 0755 -o sail -g sail /home/sail

# move test runner binary folder to the non-root's user home directory
RUN mv /root/.cache /home/sail/.cache

USER sail

# show user effective id and group - it should be non-zero
# meaning the current user "node" is not root
RUN id

ENV CYPRESS_CACHE_FOLDER=/home/sail/.cache/Cypress

Add docker\novnc\Dockerfile:

FROM alpine:3.16

ARG WWWGROUP
ARG WWWUSER

# Setup demo environment variables
ENV LANG=en_US.UTF-8 \
  LANGUAGE=en_US.UTF-8 \
  LC_ALL=en_US.UTF-8 \
  DISPLAY=:0.0

RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk update && \
    apk add \
    novnc@testing \
    bash \
    fluxbox \
    terminus-font \
    supervisor \
    tigervnc

RUN ln -s /usr/share/novnc/vnc.html /usr/share/novnc/index.html

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 8080

RUN addgroup -g ${WWWGROUP} sail
# do not log creating new user, otherwise there could be a lot of messages
RUN adduser --disabled-password --gecos "" --uid ${WWWUSER} --ingroup sail sail
RUN install -d -m 0755 -o sail -g sail /home/sail

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

And finally add docker\novnc\supervisord.conf:

[supervisord]
user=sail
nodaemon=true
logfile=/home/sail/supervisord.log
pidfile=/home/sail/supervisord.pid

[program:xvnc]
user=sail
command=/usr/bin/Xvnc -SecurityTypes=None -localhost=0 :0.0 -listen tcp -ac
autorestart=true

[program:novnc]
user=sail
command=/usr/bin/novnc_server --vnc localhost:5900 --listen 8080
autorestart=true

[program:fluxbox]
user=sail
command=fluxbox
autorestart=true
environment=HOME="/home/sail"

@parapente not sure if I'm missing something here but when I run sail npx cypress open after following all your steps, I get the following:

No version of Cypress is installed in: /home/sail/.cache/Cypress/10.10.0/Cypress

Please reinstall Cypress by running: cypress install

----------

Cypress executable not found at: /home/sail/.cache/Cypress/10.10.0/Cypress/Cypress

----------

Platform: linux-x64 (Ubuntu - 21.10)
Cypress Version: 10.10.0
parapente commented 1 year ago

@matthewknill first of all try to match the versions of cypress you want to use. In the above instructions I had

FROM cypress/included:9.7.0

because I used an old project with laravel 8. Make sure to change to the one you have installed in your project with npm.

Then you don't need to run sail npx cypress open as cypress is auto started. You just browse http://localhost:8080 and you should see novpn. Click "Connect" and from the gear on the left side of the screen choose scaling mode to remote resize.

If for some reason you close the cypress application, you can restart it running docker-compose start cypress.

I haven't used cypress 10 yet but I'm really interested in its component testing feature, so if I find something not working, I will post further instructions.

matthewknill commented 1 year ago

@matthewknill first of all try to match the versions of cypress you want to use. In the above instructions I had

FROM cypress/included:9.7.0

because I used an old project with laravel 8. Make sure to change to the one you have installed in your project with npm.

Then you don't need to run sail npx cypress open as cypress is auto started. You just browse http://localhost:8080 and you should see novpn. Click "Connect" and from the gear on the left side of the screen choose scaling mode to remote resize.

If for some reason you close the cypress application, you can restart it running docker-compose start cypress.

I haven't used cypress 10 yet but I'm really interested in its component testing feature, so if I find something not working, I will post further instructions.

Fantastic, got it working thanks! Quite annoying to get it working with WSL2 on Windows without using a container. You can use the following to make the VNC fullscreen (set Remote Resizing): image

colinmackinlay commented 1 year ago

Worked (almost) perfectly on WSL2. Thanks @matthewknill @parapente

Everything comes up in the VNC window but when running the default test I get an error failed trying to load http://laravel.test:80/ connection refused to 127.0.0.1:80.

Shouldn't it look for laravel.test on the internal Sail IP address?

UPDATE .env.cypress is initially a copy of .env and had another value for APP_URL_BASE instead of laravel.test

Once corrected everything works fine :)

colinmackinlay commented 1 year ago

Hello @matthewknill @parapente

Have either of you tried to get this working with subdomains? Specifically I'd like to to test a "tenancy for laravel" https://github.com/archtechx/tenancy application but can't find a way to get cypress to connect to tenants which are subdomains, only the central domain is ok.

@stancl - have you ever got cypress working?

stancl commented 1 year ago

I've never used it unfortunately

matthewknill commented 1 year ago

Hello @matthewknill @parapente

Have either of you tried to get this working with subdomains? Specifically I'd like to to test a "tenancy for laravel" https://github.com/archtechx/tenancy application but can't find a way to get cypress to connect to tenants which are subdomains, only the central domain is ok.

@stancl - have you ever got cypress working?

I'm actually looking to use this package in the future. You could get this working by just changing the baseUrl in cypress.config.js though right (I haven't tested this)?

matthewknill commented 1 year ago

I'm finding that sail --env-file .env.cypress up does not seem to use my .env.cypress for some reason and just uses the standard database in .env. I followed the exact procedure above and still can't get it to use a different database even after clearing the cache and everything.

parapente commented 1 year ago

@matthewknill you should probably run php artisan cypress:boilerplate to install the boilerplate code needed for testing laravel apps. If you install the boilerplate from the package it should read the .env.cypress file before every test.

colinmackinlay commented 1 year ago

@matthewknill @parapente - I've got this working for @stancl Tenancy for Laravel by configuring an alias for laravel.test in docker-compose.yml:

    networks:
      sail:
        aliases:
          - testing.laravel.test

This means that any calls to the testing hostname from cypress or dusk are resolved to the application container using dockers internal dns magic.

My complete file is:

# For more information: https://laravel.com/docs/sail
version: '3'
services:
  laravel.test:
    build:
      context: ./vendor/laravel/sail/runtimes/8.1
      dockerfile: Dockerfile
      args:
        WWWGROUP: '${WWWGROUP}'
    image: sail-8.1/app
    extra_hosts:
      - 'host.docker.internal:host-gateway'
    ports:
      - '${APP_PORT:-80}:80'
      - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
    environment:
      WWWUSER: '${WWWUSER}'
      LARAVEL_SAIL: 1
      XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
      XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
    volumes:
      - '.:/var/www/html'
    networks:
      sail:
        aliases:
          - testing.laravel.test
    depends_on:
      - mysql
      - redis
  mysql:
    build:
      context: ./docker/mysql
      dockerfile: Dockerfile
    ports:
      - '${FORWARD_DB_PORT:-3306}:3306'
    environment:
      MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
      MYSQL_ROOT_HOST: "%"
      MYSQL_DATABASE: '${DB_DATABASE}'
      MYSQL_USER: '${DB_USERNAME}'
      MYSQL_PASSWORD: '${DB_PASSWORD}'
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
    volumes:
      - 'sail-mysql:/var/lib/mysql'
      - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
    networks:
      - sail
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}" ]
      retries: 3
      timeout: 5s
  redis:
    image: 'redis:alpine'
    ports:
      - '${FORWARD_REDIS_PORT:-6379}:6379'
    volumes:
      - 'sail-redis:/data'
    networks:
      - sail
    healthcheck:
      test: [ "CMD", "redis-cli", "ping" ]
      retries: 3
      timeout: 5s
  mailhog:
    image: 'mailhog/mailhog:latest'
    ports:
      - '${FORWARD_MAILHOG_PORT:-1025}:1025'
      - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
    networks:
      - sail
  cypress:
    build:
      context: ./docker/cypress
      args:
        WWWUSER: "${WWWUSER}"
        WWWGROUP: "${WWWGROUP}"
    depends_on:
      - laravel.test
      - novnc
    environment:
      - CYPRESS_baseUrl=http://laravel.test:${APP_PORT:-80}
      - DISPLAY=novnc:0.0
    working_dir: /e2e
    entrypoint: cypress open --project /e2e
    volumes:
      - ./:/e2e
    networks:
      - sail
  novnc:
    build:
      context: ./docker/novnc
      dockerfile: Dockerfile
      args:
        WWWUSER: "${WWWUSER}"
        WWWGROUP: "${WWWGROUP}"
    ports:
      - "8080:8080"
    networks:
      - sail
  selenium:
    image: 'selenium/standalone-chrome'
    volumes:
      - '/dev/shm:/dev/shm'
    networks:
      - sail
networks:
  sail:
    driver: bridge
volumes:
  sail-mysql:
    driver: local
  sail-redis:
    driver: local
protocyber commented 1 year ago

Thank you @parapente . I have done the steps from you. But I got this error when execute sail up:

ERROR [ark-novnc 6/8] RUN addgroup -g 20 sail

parapente commented 1 year ago

@protocyber you use a value for WWWGROUP that clashes with a group that already exists in the novnc container. Use id -g to see the group your user is in and try that one instead (usually 1000+).

protocyber commented 1 year ago

I'm using mac. And by default any user is a member of staff group which has ID of 20. Should I create another group. Maybe called group username like in Linux?

Update: I have create a new group and set this as my default group

But I there is another problem, the novnc cannot start:

INFO success: novnc entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
INFO exited: novnc (exit status 1; not expected)

Meanwhile there is also error in cypress container:

cypress-1       | qemu: uncaught target signal 11 (Segmentation fault) - core dumped
cypress-1       | The Test Runner unexpectedly exited via a exit event with signal SIGSEGV
cypress-1       |
cypress-1       | Please search Cypress documentation for possible solutions:
cypress-1       |
cypress-1       | https://on.cypress.io
cypress-1       |
cypress-1       | Check if there is a GitHub issue describing this crash:
cypress-1       |
cypress-1       | https://github.com/cypress-io/cypress/issues
cypress-1       |
cypress-1       | Consider opening a new issue.
cypress-1       |
cypress-1       | ----------
cypress-1       |
cypress-1       | Platform: linux-x64 (Debian - 11.3)
cypress-1       | Cypress Version: 9.7.0
parapente commented 1 year ago

@protocyber there is a group named dialout in the novnc groups file with group id 20. Try modifying the novnc/Dockerfile by adding the following line before addgroup:

delgroup dialout
protocyber commented 1 year ago

Thank you for responding @parapente. Unfortunately the problem still the same.

@protocyber there is a group named dialout in the novnc groups file with group id 20. Try modifying the novnc/Dockerfile by adding the following line before addgroup:

delgroup dialout
parapente commented 1 year ago

@protocyber Did you return WWWGROUP to 20?

protocyber commented 1 year ago

My novnc/Dockerfile

image

Build log

image

sail up log...

image
parapente commented 1 year ago

@protocyber Here are some things to check:

  1. Take everything down using sail down and rebuild containers in case one of them still uses the wrong group number.
  2. check file permissions of your project folder in case something got set with wrong user/group id. In case your project doesn't require special file permissions your can just run chown -R <user>:<group> . inside the project folder.
  3. The segfault for cypress isn't something that you should worry about that much. If for some reason cypress gets started before fluxbox and Xvnc, it usually crashes. Running sail restart cypress should start the desktop app. Take a look at the novnc log when it starts to see why Xnvc doesn't start as it is needed for everything else.
trashbat commented 1 year ago

Thanks very much for your solution, @parapente! I needed to make a couple of additions:

parapente commented 1 year ago

You are welcome @trashbat! Indeed the alpine package for novnc is now missing websockify so your proposed solution I think is the best one you can use.

parapente commented 1 year ago

After the latest updates to Alpine Linux packages, docker fails to build the novnc container. Updating to the latest image (3.18) novnc builds correctly.

docker\novnc\Dockerfile:

FROM alpine:3.18
Thinkro commented 1 year ago

Is there a way a way to Cypress without an VNC, and still have all the features?

parapente commented 1 year ago

Is there a way a way to Cypress without an VNC, and still have all the features?

@Thinkro As Laravel Sail runs inside a Linux container you would need to use an X server for the GUI of Cypress to appear. If you are running a Linux desktop you can use xauth to allow applications from the container to appear on your screen without using vnc. If you are not on a Linux desktop, you would need an X server for Cypress to appear. It's a bit of a hassle to configure xauth and you might even end up compromising your security if you don't configure it correctly. I prefer to use novnc as it is easy to run in linux, macos and windows.

prebenvendo commented 11 months ago

Wanted to share a recipe to get Sail and Cypress to work nice together. We're running 2 instances of all our services, so that each time we wipe the db/meilisearch db we don't have to login/resync meilisearch etc.

This way you can do cypress up (we reuse sail npm run dev, so no need to do that)

https://gist.github.com/prebenvendo/6b9ae9790e4a321f5d253d3d2f016162

Let me know if anything is unclear.