diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml
new file mode 100644
index 00000000..00eb0db9
--- /dev/null
+++ b/.github/workflows/cypress.yml
@@ -0,0 +1,117 @@
+name: Cypress E2E
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+jobs:
+ cypress-run-chrome:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: [3.9]
+ containers: [1, 2]
+ services:
+ postgres:
+ image: postgres:14
+ env:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: csm_web_dev
+ ports: ["5432:5432"]
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install Python dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ - name: Install npm dependencies
+ run: |
+ npm ci
+ - name: Install Chrome 106
+ run: |
+ sudo wget --no-verbose -O /usr/src/google-chrome-stable_current_amd64.deb "http://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_106.0.5249.91-1_amd64.deb" && \
+ sudo dpkg -i /usr/src/google-chrome-stable_current_amd64.deb ; \
+ sudo apt-get install -f -y && \
+ sudo rm -f /usr/src/google-chrome-stable_current_amd64.deb
+ - name: Run Cypress
+ uses: cypress-io/github-action@v4
+ with:
+ record: true
+ build: npm run build
+ start: python csm_web/manage.py runserver
+ wait-on: http://localhost:8000
+ browser: chrome
+ parallel: true
+ group: Tests on Chrome 106
+ env:
+ SECRET_KEY: ${{ secrets.SECRET_KEY }}
+ DJANGO_ENV: dev
+ POSTGRES_PASSWORD: postgres
+ CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+ # pass GitHub token to allow accurately detecting a build vs a re-run build
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # better cypress run titles
+ COMMIT_INFO_MESSAGE: ${{github.event.pull_request.title}}
+ COMMIT_INFO_SHA: ${{github.event.pull_request.head.sha}}
+ cypress-run-firefox:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: [3.9]
+ containers: [1, 2]
+ services:
+ postgres:
+ image: postgres:14
+ env:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: csm_web_dev
+ ports: ["5432:5432"]
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install Python dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ - name: Install npm dependencies
+ run: |
+ npm ci
+ - name: Install Firefox 106
+ run: |
+ sudo wget --no-verbose -O /tmp/firefox.tar.bz2 https://download-installer.cdn.mozilla.net/pub/firefox/releases/106.0.2/linux-x86_64/en-US/firefox-106.0.2.tar.bz2 && \
+ sudo tar -C /opt -xjf /tmp/firefox.tar.bz2 && \
+ sudo rm /tmp/firefox.tar.bz2 && \
+ sudo ln -fs /opt/firefox/firefox /usr/bin/firefox
+ - name: Run Cypress
+ uses: cypress-io/github-action@v4
+ with:
+ record: true
+ build: npm run build
+ start: python csm_web/manage.py runserver
+ wait-on: http://localhost:8000
+ browser: firefox
+ parallel: true
+ group: Tests on Firefox 106
+ env:
+ SECRET_KEY: ${{ secrets.SECRET_KEY }}
+ DJANGO_ENV: dev
+ POSTGRES_PASSWORD: postgres
+ CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+ # pass GitHub token to allow accurately detecting a build vs a re-run build
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # better cypress run titles
+ COMMIT_INFO_MESSAGE: ${{github.event.pull_request.title}}
+ COMMIT_INFO_SHA: ${{github.event.pull_request.head.sha}}
diff --git a/.gitignore b/.gitignore
index 8d35fa79..346219a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,8 @@ coverage.xml
*.cover
.hypothesis/
.pytest_cache/
+cypress/videos/
+cypress/screenshots/
# Translations
*.mo
diff --git a/csm_web/csm_web/settings.py b/csm_web/csm_web/settings.py
index cab47f3f..e9355659 100644
--- a/csm_web/csm_web/settings.py
+++ b/csm_web/csm_web/settings.py
@@ -236,6 +236,14 @@
"rest_framework.renderers.BrowsableAPIRenderer"
)
+# Cache
+CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
+ 'LOCATION': 'db_cache_table',
+ }
+}
+
# Logging
LOGGING = {
'version': 1,
diff --git a/csm_web/frontend/src/components/section/CoordinatorAddStudentModal.tsx b/csm_web/frontend/src/components/section/CoordinatorAddStudentModal.tsx
index 8bd7f550..bd0e3aa5 100644
--- a/csm_web/frontend/src/components/section/CoordinatorAddStudentModal.tsx
+++ b/csm_web/frontend/src/components/section/CoordinatorAddStudentModal.tsx
@@ -205,13 +205,13 @@ export function CoordinatorAddStudentModal({
-
{conflictDetail}
@@ -360,7 +360,7 @@ export function CoordinatorAddStudentModal({
>
×
- {email_obj.email}
+ {email_obj.email}
@@ -402,7 +402,7 @@ export function CoordinatorAddStudentModal({
>
×
- {email_obj.email}
+ {email_obj.email}
diff --git a/csm_web/frontend/src/tests/section/StudentDropper.test.tsx b/csm_web/frontend/src/tests/section/StudentDropper.test.tsx
index d5fa3e8d..b8b7ef66 100644
--- a/csm_web/frontend/src/tests/section/StudentDropper.test.tsx
+++ b/csm_web/frontend/src/tests/section/StudentDropper.test.tsx
@@ -3,6 +3,7 @@ import { act, fireEvent, render, waitFor } from "@testing-library/react";
import React from "react";
import StudentDropper from "../../components/section/StudentDropper";
import * as api from "../../utils/api";
+import { testQueryClientWrapper } from "../utils";
// mock modal
jest.mock("../../components/Modal", () => {
@@ -21,14 +22,16 @@ jest.mock("../../components/Modal", () => {
describe("StudentDropper", () => {
it("should render correctly without interaction", () => {
- const reloadSection = jest.fn();
- const component = render();
+ const component = render(, {
+ wrapper: testQueryClientWrapper
+ });
expect(component.asFragment()).toMatchSnapshot();
});
it("should render modal correctly after clicking x", () => {
- const reloadSection = jest.fn();
- const component = render();
+ const component = render(, {
+ wrapper: testQueryClientWrapper
+ });
act(() => {
// click drop button to bring up modal
@@ -39,8 +42,9 @@ describe("StudentDropper", () => {
});
it("should close modal correctly", () => {
- const reloadSection = jest.fn();
- const component = render();
+ const component = render(, {
+ wrapper: testQueryClientWrapper
+ });
act(() => {
// click drop button to bring up modal
@@ -68,8 +72,9 @@ describe("StudentDropper", () => {
return null as any;
});
- const reloadSection = jest.fn();
- const component = render();
+ const component = render(, {
+ wrapper: testQueryClientWrapper
+ });
// click drop button to bring up modal
act(() => {
@@ -108,7 +113,6 @@ describe("StudentDropper", () => {
// wait for fetch to finish
waitFor(() => {
expect(spyFetchWithMethod).toHaveBeenCalled();
- expect(reloadSection).toHaveBeenCalled();
});
});
@@ -125,8 +129,9 @@ describe("StudentDropper", () => {
return null as any;
});
- const reloadSection = jest.fn();
- const component = render();
+ const component = render(, {
+ wrapper: testQueryClientWrapper
+ });
// click drop button to bring up modal
act(() => {
@@ -179,7 +184,6 @@ describe("StudentDropper", () => {
// wait for fetch to finish
waitFor(() => {
expect(spyFetchWithMethod).toHaveBeenCalled();
- expect(reloadSection).toHaveBeenCalled();
});
});
});
diff --git a/csm_web/frontend/src/tests/utils.tsx b/csm_web/frontend/src/tests/utils.tsx
new file mode 100644
index 00000000..f5629196
--- /dev/null
+++ b/csm_web/frontend/src/tests/utils.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+
+export const testQueryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false
+ }
+ }
+});
+
+/**
+ * Wrap an element with a query client provider, so that react-query functions correctly.
+ */
+export const testQueryClientWrapper = ({ children }: { children: React.ReactElement }) => (
+ {children}
+);
diff --git a/csm_web/scheduler/management/commands/createtestuser.py b/csm_web/scheduler/management/commands/createtestuser.py
new file mode 100644
index 00000000..e71eb8ec
--- /dev/null
+++ b/csm_web/scheduler/management/commands/createtestuser.py
@@ -0,0 +1,25 @@
+from django.core.management import BaseCommand
+from scheduler.models import User
+
+
+class Command(BaseCommand):
+ help = "Populates database with a single test user for testing."
+
+ def add_arguments(self, parser):
+ parser.add_argument(
+ "--silent", action="store_true", help="no stdout during execution"
+ )
+
+ def handle(self, *args, **options):
+ demo_user = User.objects.create(
+ username="demo_user",
+ email="demo_user@berkeley.edu",
+ first_name="Demo",
+ last_name="User",
+ )
+ demo_user.is_staff = True
+ demo_user.is_superuser = True
+ demo_user.set_password("pass")
+ demo_user.save()
+ if "silent" not in options or not options["silent"]:
+ print("Created demo user with username 'demo_user' and password 'pass'")
diff --git a/csm_web/scheduler/views/section.py b/csm_web/scheduler/views/section.py
index c0da8c0b..1d6fa0a3 100644
--- a/csm_web/scheduler/views/section.py
+++ b/csm_web/scheduler/views/section.py
@@ -321,7 +321,9 @@ class BanAction:
)
elif student_queryset.count() == 0:
# check if the user can actually enroll in the section
- student_user = User.objects.get(email=email)
+ student_user, _ = User.objects.get_or_create(
+ username=email.split('@')[0], email=email
+ )
if (
student_user.id not in course_coords
and student_user.can_enroll_in_course(section.mentor.course, bypass_enrollment_time=True)
diff --git a/cypress.config.ts b/cypress.config.ts
new file mode 100644
index 00000000..79fd8b6c
--- /dev/null
+++ b/cypress.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from "cypress";
+
+export default defineConfig({
+ e2e: {
+ projectId: "ar111y",
+ baseUrl: "http://localhost:8000"
+ }
+});
diff --git a/cypress/.eslintrc.json b/cypress/.eslintrc.json
new file mode 100644
index 00000000..0f1b1514
--- /dev/null
+++ b/cypress/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": ["plugin:cypress/recommended"]
+}
diff --git a/cypress/db/.pylintrc b/cypress/db/.pylintrc
new file mode 100644
index 00000000..4a1e7917
--- /dev/null
+++ b/cypress/db/.pylintrc
@@ -0,0 +1,2 @@
+[tool.pylint.main]
+load-plugins = ["pylint_django"]
diff --git a/cypress/db/_setup.py b/cypress/db/_setup.py
new file mode 100644
index 00000000..f05f7d87
--- /dev/null
+++ b/cypress/db/_setup.py
@@ -0,0 +1,106 @@
+import importlib
+import os
+import re
+import sys
+from pathlib import Path
+
+import django
+from django.core.cache import cache
+from django.core.management import call_command
+
+CWD = os.getcwd()
+CACHE_KEY = "CYPRESS_LAST_FUNCTION"
+CACHE_TIMEOUT = 60 * 60 * 24
+CYPRESS_SETUP_ROOT = os.path.join(CWD, "cypress", "db")
+sys.path.append(os.path.join(CWD, "csm_web"))
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "csm_web.settings")
+
+
+def setup_database(script_path: str, func_name: str):
+ # set up django settings
+ django.setup()
+
+ call_command("flush", interactive=False)
+
+ # load function from script (importlib magic)
+ location = (Path(CYPRESS_SETUP_ROOT) / script_path).with_suffix(".py")
+ assert location.is_file()
+
+ spec = importlib.util.spec_from_file_location("cypress_setup", location)
+ cypress_setup_module = importlib.util.module_from_spec(spec)
+ sys.modules["cypress_setup"] = cypress_setup_module
+ spec.loader.exec_module(cypress_setup_module)
+ cypress_setup_func = getattr(cypress_setup_module, func_name)
+
+ # run the function
+ cypress_setup_func()
+
+
+def main(script_path: str, func_name: str, force=False, mutate=False, init=False):
+ if init:
+ os.chdir("csm_web")
+ django.setup()
+ call_command("migrate", verbosity=0)
+ call_command("createcachetable")
+ cache.delete(CACHE_KEY)
+ os.chdir("..")
+ return
+
+ # validate args
+ assert re.fullmatch(r"^$|^[a-zA-Z0-9_/\.\-]+$", script_path)
+ assert re.fullmatch(r"^[a-zA-Z0-9_]+$", func_name)
+
+ cache_val = cache.get(CACHE_KEY)
+
+ if force or cache_val != (script_path, func_name):
+ setup_database(script_path, func_name)
+
+ if mutate:
+ # if we have a mutation, then the next test should always flush
+ # and set up the database again
+ cache.delete(CACHE_KEY)
+ else:
+ cache.set(CACHE_KEY, (script_path, func_name), CACHE_TIMEOUT)
+
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser(
+ "setup",
+ description="Set up a Django database for Cypress tests",
+ )
+
+ parser.add_argument(
+ "script_path",
+ type=str,
+ nargs="?",
+ help="path to the script, relative to CYPRESS_SETUP_ROOT",
+ )
+ parser.add_argument(
+ "func_name",
+ type=str,
+ nargs="?",
+ help="function in the script to run",
+ )
+ parser.add_argument(
+ "--force", action="store_true", help="whether to force a database flush"
+ )
+ parser.add_argument(
+ "--mutate", action="store_true", help="whether the test modifies the database"
+ )
+ parser.add_argument(
+ "--init",
+ action="store_true",
+ help="initialize the database; run migrate and createcachetable",
+ )
+
+ args = parser.parse_args()
+
+ main(
+ args.script_path,
+ args.func_name,
+ force=args.force,
+ mutate=args.mutate,
+ init=args.init,
+ )
diff --git a/cypress/db/coordinator-student-course.py b/cypress/db/coordinator-student-course.py
new file mode 100644
index 00000000..d960ad38
--- /dev/null
+++ b/cypress/db/coordinator-student-course.py
@@ -0,0 +1,239 @@
+import datetime
+
+from django.core.management import call_command
+from django.utils import timezone
+from scheduler.factories import StudentFactory
+from scheduler.models import Coordinator, Course, Mentor, Section, Spacetime, User
+
+MINUS_5 = timezone.now() - datetime.timedelta(days=5)
+MINUS_3 = timezone.now() - datetime.timedelta(days=3)
+MINUS_1 = timezone.now() - datetime.timedelta(days=1)
+PLUS_3 = timezone.now() + datetime.timedelta(days=3)
+PLUS_5 = timezone.now() + datetime.timedelta(days=5)
+PLUS_10 = timezone.now() + datetime.timedelta(days=10)
+PLUS_15 = timezone.now() + datetime.timedelta(days=15)
+PLUS_30 = timezone.now() + datetime.timedelta(days=30)
+
+
+def _setup(cs61a):
+ # create mentors
+ for i in range(1, 7):
+ mentor_user = User.objects.create(
+ username=f"test_mentor_{i}",
+ email=f"test_mentor_{i}@berkeley.edu",
+ first_name="Test",
+ last_name=f"Mentor {i}",
+ )
+ Mentor.objects.create(user=mentor_user, course=cs61a)
+
+ # Monday sections
+
+ section = Section.objects.create(
+ mentor=Mentor.objects.get(user__username="test_mentor_1"),
+ capacity=5,
+ description="Affinity section",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Monday",
+ start_time="11:00:00",
+ duration="01:00:00",
+ location="Cory 400",
+ )
+ # students in section
+ StudentFactory.create_batch(3, course=cs61a, section=section)
+
+ section = Section.objects.create(
+ mentor=Mentor.objects.get(user__username="test_mentor_2"),
+ capacity=3,
+ description="",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Monday",
+ start_time="12:00:00",
+ duration="01:30:00",
+ location="Cory 300",
+ )
+ StudentFactory.create_batch(3, course=cs61a, section=section)
+
+ section = Section.objects.create(
+ mentor=Mentor.objects.get(user__username="test_mentor_3"),
+ capacity=4,
+ description="description",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Monday",
+ start_time="16:00:00",
+ duration="01:00:00",
+ location="Soda 380",
+ )
+
+ # Tuesday/Wednesday sections
+
+ section = Section.objects.create(
+ mentor=Mentor.objects.get(user__username="test_mentor_4"),
+ capacity=3,
+ description="Online",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Tuesday",
+ start_time="16:00:00",
+ duration="01:00:00",
+ location="Cory 212",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Wednesday",
+ start_time="16:00:00",
+ duration="01:00:00",
+ location="Cory 400",
+ )
+
+ section = Section.objects.create(
+ mentor=Mentor.objects.get(user__username="test_mentor_5"),
+ capacity=4,
+ description="Online",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Tuesday",
+ start_time="11:00:00",
+ duration="01:30:00",
+ location="Cory 212",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Wednesday",
+ start_time="12:00:00",
+ duration="01:00:00",
+ location="Soda 286",
+ )
+ StudentFactory.create_batch(4, course=cs61a, section=section)
+
+ # Thursday sections
+
+ section = Section.objects.create(
+ mentor=Mentor.objects.get(user__username="test_mentor_6"),
+ capacity=3,
+ description="",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Thursday",
+ start_time="13:00:00",
+ duration="01:00:00",
+ location="Soda 300",
+ )
+ StudentFactory.create_batch(3, course=cs61a, section=section)
+
+
+def _setup_user():
+ call_command("createtestuser", silent=True)
+
+
+def _setup_course_open():
+ return Course.objects.create(
+ name="CS61A",
+ title="Structure and Interpretation of Computer Programs",
+ permitted_absences=2,
+ enrollment_start=MINUS_5,
+ section_start=MINUS_1,
+ enrollment_end=PLUS_15,
+ valid_until=PLUS_30,
+ )
+
+
+def _setup_course_closed():
+ return Course.objects.create(
+ name="CS61A",
+ title="Structure and Interpretation of Computer Programs",
+ permitted_absences=2,
+ enrollment_start=PLUS_5,
+ section_start=PLUS_10,
+ enrollment_end=PLUS_15,
+ valid_until=PLUS_30,
+ )
+
+
+"""
+Coordinator setup functions
+"""
+
+
+def coord_setup_open():
+ _setup_user()
+ cs61a = _setup_course_open()
+
+ # set demo_user as coordinator
+ Coordinator.objects.create(
+ user=User.objects.get(username="demo_user"), course=cs61a
+ )
+ _setup(cs61a)
+
+
+def coord_setup_closed():
+ _setup_user()
+ cs61a = _setup_course_closed()
+
+ # set demo_user as coordinator
+ Coordinator.objects.create(
+ user=User.objects.get(username="demo_user"), course=cs61a
+ )
+ _setup(cs61a)
+
+
+def coord_setup_closed_priority():
+ coord_setup_closed()
+
+ demo_user = User.objects.get(username="demo_user")
+ demo_user.priority_enrollment = PLUS_3
+ demo_user.save()
+
+
+"""
+Student setup functions
+"""
+
+
+def student_setup_open():
+ """
+ Open course; no priority enrollment
+ """
+ _setup_user()
+ cs61a = _setup_course_open()
+ _setup(cs61a)
+
+
+def student_setup_closed():
+ """
+ Closed course; no priority enrollment
+ """
+ _setup_user()
+ cs61a = _setup_course_closed()
+ _setup(cs61a)
+
+
+def student_setup_open_priority():
+ """
+ Open course because prior priority enrollment;
+ otherwise the course should be clsoed
+ """
+ student_setup_closed()
+
+ demo_user = User.objects.get(username="demo_user")
+ demo_user.priority_enrollment = MINUS_3
+ demo_user.save()
+
+
+def student_setup_closed_priority():
+ """
+ Closed course, even with priority enrollment
+ """
+ student_setup_closed()
+
+ demo_user = User.objects.get(username="demo_user")
+ demo_user.priority_enrollment = PLUS_3
+ demo_user.save()
diff --git a/cypress/db/course-menu.py b/cypress/db/course-menu.py
new file mode 100644
index 00000000..a1ebf0b4
--- /dev/null
+++ b/cypress/db/course-menu.py
@@ -0,0 +1,95 @@
+import datetime
+
+from django.core.management import call_command
+from django.utils import timezone
+from scheduler.models import Course, Mentor, Section, Spacetime, User
+
+MINUS_15 = timezone.now() - datetime.timedelta(days=15)
+MINUS_10 = timezone.now() - datetime.timedelta(days=10)
+PLUS_10 = timezone.now() + datetime.timedelta(days=10)
+PLUS_15 = timezone.now() + datetime.timedelta(days=15)
+PLUS_20 = timezone.now() + datetime.timedelta(days=20)
+PLUS_25 = timezone.now() + datetime.timedelta(days=25)
+# reserved for priority enrollment
+MINUS_5 = timezone.now() - datetime.timedelta(days=5)
+PLUS_5 = timezone.now() + datetime.timedelta(days=5)
+
+
+def setup():
+ # create demo_user
+ call_command("createtestuser", silent=True)
+
+ # NOW < start < end
+ cs61a = Course.objects.create(
+ name="CS61A",
+ title="Structure and Interpretation of Computer Programs",
+ permitted_absences=2,
+ # NOW
+ enrollment_start=PLUS_10,
+ section_start=PLUS_15,
+ enrollment_end=PLUS_20,
+ valid_until=PLUS_25,
+ )
+ # start < NOW < end
+ Course.objects.create(
+ name="CS61B",
+ title="Data Structures",
+ enrollment_start=MINUS_15,
+ section_start=MINUS_10,
+ # NOW
+ enrollment_end=PLUS_10,
+ valid_until=PLUS_15,
+ permitted_absences=2,
+ )
+ # start < end < NOW
+ Course.objects.create(
+ name="CS61C",
+ title="Machine Structures",
+ permitted_absences=2,
+ enrollment_start=MINUS_15,
+ section_start=MINUS_10,
+ enrollment_end=MINUS_10,
+ # NOW
+ valid_until=PLUS_15,
+ )
+
+ mentor_1_user = User.objects.create(
+ username="mentor_1",
+ email="mentor_1@berkeley.edu",
+ first_name="Mentor",
+ last_name="1",
+ )
+ mentor_1 = Mentor.objects.create(user=mentor_1_user, course=cs61a)
+ section = Section.objects.create(
+ mentor=mentor_1,
+ capacity=5,
+ description="",
+ )
+ Spacetime.objects.create(
+ location="Cory 400",
+ start_time="11:00:00",
+ duration="01:00:00",
+ day_of_week="Monday",
+ section=section,
+ )
+ Spacetime.objects.create(
+ location="Cory 400",
+ start_time="11:00:00",
+ duration="01:00:00",
+ day_of_week="Tuesday",
+ section=section,
+ )
+
+
+def setup_priority_enrollment_past():
+ setup()
+ user = User.objects.get(username="demo_user")
+ user.priority_enrollment = MINUS_5
+ user.save()
+
+
+def setup_priority_enrollment_future():
+ setup()
+ user = User.objects.get(username="demo_user")
+ user.priority_enrollment = PLUS_5
+ user.save()
diff --git a/cypress/db/login.py b/cypress/db/login.py
new file mode 100644
index 00000000..e579c0b5
--- /dev/null
+++ b/cypress/db/login.py
@@ -0,0 +1,5 @@
+from django.core.management import call_command
+
+
+def setup():
+ call_command("createtestuser", silent=True)
diff --git a/cypress/db/mentor-section.py b/cypress/db/mentor-section.py
new file mode 100644
index 00000000..86735c89
--- /dev/null
+++ b/cypress/db/mentor-section.py
@@ -0,0 +1,178 @@
+import datetime
+from typing import Literal, Union
+
+from django.core.management import call_command
+from django.utils import timezone
+from scheduler.factories import MentorFactory, StudentFactory, UserFactory
+from scheduler.models import (
+ Attendance,
+ Coordinator,
+ Course,
+ Mentor,
+ Section,
+ SectionOccurrence,
+ Spacetime,
+ Student,
+ User,
+)
+
+NOW = timezone.now()
+
+
+def NOW_MINUS(days: int):
+ return timezone.now() - datetime.timedelta(days=days)
+
+
+def NOW_PLUS(days: int):
+ return timezone.now() + datetime.timedelta(days=days)
+
+
+def _setup_common(role: Union[Literal["mentor"], Literal["coordinator"]]):
+ call_command("createtestuser", silent=True)
+
+ user = User.objects.get(username="demo_user")
+ cs61a = Course.objects.create(
+ name="CS61A",
+ title="Structure and Interpretation of Computer Programs",
+ permitted_absences=2,
+ enrollment_start=NOW_MINUS(30),
+ section_start=NOW_MINUS(15),
+ enrollment_end=NOW_PLUS(15),
+ valid_until=NOW_PLUS(30),
+ )
+
+ if role == "mentor":
+ # create mentor
+ mentor = Mentor.objects.create(user=user, course=cs61a)
+ elif role == "coordinator":
+ # create coordinator
+ Coordinator.objects.create(user=user, course=cs61a)
+ mentor_user = User.objects.create(
+ username="testmentor",
+ email="testmentor@berkeley.edu",
+ first_name="Test",
+ last_name="Mentor",
+ )
+ mentor = Mentor.objects.create(user=mentor_user, course=cs61a)
+
+ # create section
+ section = Section.objects.create(
+ mentor=mentor, capacity=5, description="test section"
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Monday",
+ start_time="11:00:00",
+ duration="01:00:00",
+ location="Cory 400",
+ )
+ Spacetime.objects.create(
+ section=section,
+ day_of_week="Tuesday",
+ start_time="14:00:00",
+ duration="01:00:00",
+ location="Soda 380",
+ )
+
+ # create students (out of order on purpose)
+ for prefix in ("A", "D", "C", "B"):
+ new_user = User.objects.create(
+ username=f"{prefix}_student",
+ first_name=prefix,
+ last_name="Student",
+ email=f"{prefix}_student@berkeley.edu",
+ )
+ Student.objects.create(user=new_user, course=cs61a, section=section)
+
+ # create additional users (1 through 5)
+ for i in range(1, 6):
+ User.objects.create(
+ username=f"testuser{i}",
+ first_name="Test",
+ last_name=f"User {i}",
+ email=f"testuser{i}@berkeley.edu",
+ )
+
+
+def setup_mentor_section():
+ _setup_common(role="mentor")
+
+ user = User.objects.get(username="demo_user")
+ section = Section.objects.get(mentor__user=user)
+ students = section.students.all()
+
+ # remove automatic attendances
+ SectionOccurrence.objects.filter(section=section).delete()
+
+ # replace with fixed section occurrences and attendances
+ so_now = SectionOccurrence.objects.create(section=section, date=NOW.date())
+ so_tomorrow = SectionOccurrence.objects.create(
+ section=section, date=NOW_PLUS(1).date()
+ )
+
+ # create attendances for each student
+ for student in students:
+ # everybody present for today
+ Attendance.objects.create(
+ presence="PR", student=student, sectionOccurrence=so_now
+ )
+ # blank for tomorrow
+ Attendance.objects.create(
+ student=student, sectionOccurrence=so_tomorrow)
+
+
+def setup_multiple_mentor_sections():
+ _setup_common(role="coordinator")
+
+ cs61a = Course.objects.get(name="CS61A")
+
+ # set up another mentor with a section
+ user_1 = User.objects.create(
+ username="user1", email="user1@berkeley.edu", first_name="User", last_name="One"
+ )
+ mentor_1 = Mentor.objects.create(user=user_1, course=cs61a)
+ section_1 = Section.objects.create(mentor=mentor_1, capacity=5)
+ Spacetime.objects.create(
+ section=section_1,
+ day_of_week="Wednesday",
+ start_time="11:00:00",
+ duration="01:00:00",
+ location="Cory 400",
+ )
+ Spacetime.objects.create(
+ section=section_1,
+ day_of_week="Thursday",
+ start_time="14:00:00",
+ duration="01:00:00",
+ location="Soda 380",
+ )
+
+ # set up new student in the section
+ user_2 = User.objects.create(
+ username="user2", email="user2@berkeley.edu", first_name="User", last_name="Two"
+ )
+ Student.objects.create(user=user_2, course=cs61a, section=section_1)
+
+ # set up banned student in the section
+ banned_user = User.objects.create(
+ username="banned_student",
+ email="banned_student@berkeley.edu",
+ first_name="banned",
+ last_name="student",
+ )
+ Student.objects.create(
+ user=banned_user, course=cs61a, section=section_1, active=False, banned=True
+ )
+
+
+def setup_full_section():
+ setup_multiple_mentor_sections()
+ cs61a = Course.objects.get(name="CS61A")
+ section = Section.objects.get(mentor__user__username="testmentor")
+ user = User.objects.create(
+ username="E_student",
+ email="E_student@berkeley.edu",
+ first_name="E",
+ last_name="student",
+ )
+ Student.objects.create(user=user, course=cs61a, section=section)
diff --git a/cypress/e2e/course/coordinator-course.cy.ts b/cypress/e2e/course/coordinator-course.cy.ts
new file mode 100644
index 00000000..43474981
--- /dev/null
+++ b/cypress/e2e/course/coordinator-course.cy.ts
@@ -0,0 +1,307 @@
+before(() => {
+ // initialize the database and cache
+ cy.initDB();
+});
+
+/**
+ * Converts a time of the form hh:mm a/pm into a Date object
+ */
+const timeStringToDate = (time: string): Date => {
+ // extract hours, minutes, am/pm
+ const [_, hours_str, minutes, ampm] = time.match(/(\d\d?):(\d\d) (AM|PM)/);
+
+ let hours = parseInt(hours_str);
+ if (ampm === "PM" && hours !== 12) {
+ hours += 12;
+ } else if (ampm === "AM" && hours === 12) {
+ hours = 0;
+ }
+ const formatted_hours = hours.toString().padStart(2, "0");
+ // put in iso format to ensure parse succeeds
+ return new Date(Date.parse(`2020-01-01T${formatted_hours}:${minutes}:00.000`));
+};
+
+/**
+ * Check that the capacity of a section card is as expected
+ */
+const checkCapacity = (text: string, isFull: boolean = false) => {
+ const groups = text.trim().match(/^(\d+)\/(\d+)$/i);
+ if (isFull) {
+ expect(parseInt(groups[1]) / parseInt(groups[2])).to.be.eq(1);
+ } else {
+ expect(parseInt(groups[1]) / parseInt(groups[2])).to.be.lt(1);
+ }
+};
+
+/**
+ * Check that the cards are in chronological order
+ */
+const checkCardOrder = () => {
+ let prevTime = null;
+ cy.get('[title="Time"]').each($el => {
+ const text = $el.text().trim();
+ // time of form [day] [start]-[end] [AM/PM]
+ // or of form [day] [start] [AM/PM]-[end] [AM/PM]
+ const matches = text.match(/\w+ (\d\d?:\d\d(?: AM| PM)?)-(\d\d?:\d\d (?:A|P)M)/g);
+ let sectionTime = null;
+ for (const substr of matches) {
+ // get groups in this match
+ const match = substr.match(/\w+ (\d\d?:\d\d(?: AM| PM)?)-(\d\d?:\d\d (?:A|P)M)/);
+ let start = match[1];
+ const end_ampm = match[2].match(/AM|PM/i)[0];
+ if (start.match(/am|pm/i) === null) {
+ // doesn't contain AM/PM, so take from the end time
+ start += " " + end_ampm;
+ }
+ const startTimeObject = timeStringToDate(start);
+ if (sectionTime === null || sectionTime > startTimeObject) {
+ sectionTime = startTimeObject;
+ }
+ }
+
+ if (prevTime !== null) {
+ // should be chronological
+ expect(prevTime).to.be.lte(sectionTime);
+ }
+ prevTime = sectionTime;
+ });
+};
+
+describe("coordinator course view", () => {
+ it("should display all section information when course is open", () => {
+ cy.setupDB("coordinator-student-course", "coord_setup_open");
+ cy.login();
+
+ // visit the course section page
+ cy.visit("/courses/1");
+
+ // === buttons and course information ===
+
+ // course title should be correct
+ cy.get(".course-title").invoke("text").should("match", /cs61a/i);
+
+ // should show M, Tu/W, Th buttons, all visible
+ cy.get(".day-btn").should("have.length", 3).should("be.visible");
+ cy.get(".day-btn.active")
+ // should have only one active tab
+ .should("have.length", 1)
+ // should default to Monday sections
+ .should("be.visible")
+ .invoke("text")
+ .should("match", /^M$/i);
+
+ // === Monday section cards ===
+
+ // should only show sections with space
+ cy.get(".section-card")
+ // should have two cards
+ .should("have.length", 2)
+ .each($el => {
+ cy.wrap($el)
+ .should("be.visible")
+ .within(() => {
+ // should have "Monday" somewhere in it
+ cy.get('[title="Time"]')
+ .invoke("text")
+ .should("match", /Monday/i);
+ // should show descriptions
+ cy.get(".section-card-description").should("be.visible");
+ // should show "manage" button
+ cy.contains(".section-card-footer", /manage/i).should("be.visible");
+
+ // should not be full
+ cy.get('[title="Current enrollment"]')
+ .invoke("text")
+ .invoke("trim")
+ .should("match", /^\d+\/\d+$/i)
+ .then(checkCapacity);
+ });
+ });
+
+ // should show sections in order by start time
+ checkCardOrder();
+
+ // now show unavailable sections
+ cy.get("#show-unavailable-toggle").click();
+
+ cy.get(".section-card")
+ // should now have three cards
+ .should("have.length", 3)
+ .each($el => {
+ cy.wrap($el)
+ .should("be.visible")
+ // should have "Monday" somewhere in it
+ .find('[title="Time"]')
+ .invoke("text")
+ .should("match", /Monday/i);
+ });
+
+ // one section should be full
+ cy.get(".section-card.full")
+ .should("have.length", 1)
+ .within(() => {
+ // should be full
+ cy.get('[title="Current enrollment"]')
+ .invoke("text")
+ .invoke("trim")
+ .should("match", /^\d+\/\d+$/i)
+ .then(text => checkCapacity(text, true));
+ // should not have a description
+ cy.get(".section-card-description").should("not.exist");
+ });
+
+ // should show sections in order by start time
+ checkCardOrder();
+
+ cy.get("#show-unavailable-toggle").click(); // reset for next day
+
+ // === Tuesday/Wednesday section cards ===
+ cy.contains(".day-btn", /tu\/w/i).click().should("have.class", "active");
+
+ // should only show sections with space
+ cy.get(".section-card")
+ // should have one card
+ .should("have.length", 1)
+ .should("be.visible")
+ .within(() => {
+ // should have both "Tuesday" and "Wednesday" somewhere in it
+ cy.get('[title="Time"]')
+ .invoke("text")
+ .then(text => {
+ expect(text).to.match(/Tuesday/i);
+ expect(text).to.match(/Wednesday/i);
+ });
+ // should show descriptions (all for Tu/W are online)
+ cy.get(".section-card-description")
+ .should("be.visible")
+ .invoke("text")
+ .should("match", /online/i);
+ // should show "manage" button
+ cy.contains(".csm-btn", /manage/i).should("be.visible");
+
+ // should not be full
+ cy.get('[title="Current enrollment"]')
+ .invoke("text")
+ .invoke("trim")
+ .should("match", /^\d+\/\d+$/i)
+ .then(checkCapacity);
+ });
+
+ // now show unavailable sections
+ cy.get("#show-unavailable-toggle").click();
+
+ cy.get(".section-card")
+ // should now have two cards
+ .should("have.length", 2)
+ .each($el => {
+ cy.wrap($el)
+ .should("be.visible")
+ .within(() => {
+ // should have both "Tuesday" and "Wednesday" somewhere in it
+ cy.get('[title="Time"]')
+ .invoke("text")
+ .then(text => {
+ expect(text).to.match(/Tuesday/i);
+ expect(text).to.match(/Wednesday/i);
+ });
+ // should show descriptions (all for Tu/W are online)
+ cy.get(".section-card-description")
+ .should("be.visible")
+ .invoke("text")
+ .should("match", /online/i);
+ });
+ });
+
+ // one section should be full
+ cy.get(".section-card.full")
+ .should("have.length", 1)
+ // should be full
+ .find('[title="Current enrollment"]')
+ .invoke("text")
+ .invoke("trim")
+ .should("match", /^\d+\/\d+$/i)
+ .then(text => checkCapacity(text, true));
+
+ // should show sections in order by start time
+ checkCardOrder();
+
+ cy.get("#show-unavailable-toggle").click(); // reset for next day
+
+ // === Thursday section cards ===
+ cy.get(".day-btn").contains(/th/i).click().should("have.class", "active");
+
+ // should show no sections by default
+ cy.get(".section-card").should("not.exist");
+ cy.get("#course-section-list-empty").should("be.visible");
+
+ // now show unavailable sections
+ cy.get("#show-unavailable-toggle").click();
+
+ // should have one full section
+ cy.get("#course-section-list-empty").should("not.exist");
+ cy.get(".section-card")
+ .should("have.length", 1)
+ .should("be.visible")
+ .should("have.class", "full")
+ .within(() => {
+ // should have "Thursday" somewhere in it
+ cy.get('[title="Time"]')
+ .invoke("text")
+ .should("match", /Thursday/i);
+ // should have no description
+ cy.get(".section-card-description").should("not.exist");
+ // should be full
+ cy.get('[title="Current enrollment"]')
+ .invoke("text")
+ .invoke("trim")
+ .should("match", /^\d+\/\d+$/i)
+ .then(text => checkCapacity(text, true));
+ });
+ });
+
+ context("when the course is closed", () => {
+ // these tests are less comprehensive,
+ // under the assumption that basically all of the layout should stay the same
+ it("should display information with no priority enrollment", () => {
+ cy.setupDB("coordinator-student-course", "coord_setup_closed");
+ cy.login();
+ cy.visit("/courses/1");
+
+ // should display enrollment start time
+ cy.get("#course-enrollment-open-status")
+ .should("be.visible")
+ // should not include anything about priority enrollment,
+ // since the user has no priority enrollment time
+ .invoke("text")
+ .should("not.match", /priority/i);
+
+ // should still be able to manage sections
+ cy.get(".section-card .section-card-footer").each($el => {
+ cy.wrap($el)
+ .invoke("text")
+ .should("match", /manage/i);
+ });
+ });
+
+ it("should display information with priority enrollment", () => {
+ cy.setupDB("coordinator-student-course", "coord_setup_closed_priority");
+ cy.login();
+ cy.visit("/courses/1");
+
+ // should display enrollment start time
+ cy.get("#course-enrollment-open-status")
+ .should("be.visible")
+ // should not include anything about priority enrollment,
+ // since the user has no priority enrollment time
+ .invoke("text")
+ .should("match", /priority/i);
+
+ // should still be able to manage sections
+ cy.get(".section-card .section-card-footer").each($el => {
+ cy.wrap($el)
+ .invoke("text")
+ .should("match", /manage/i);
+ });
+ });
+ });
+});
diff --git a/cypress/e2e/course/course-menu.cy.ts b/cypress/e2e/course/course-menu.cy.ts
new file mode 100644
index 00000000..9321aaf0
--- /dev/null
+++ b/cypress/e2e/course/course-menu.cy.ts
@@ -0,0 +1,115 @@
+before(() => {
+ // initialize the database and cache
+ cy.initDB();
+});
+
+describe("course menu", () => {
+ it("should be accessible from home page, can navigate to course pages", () => {
+ // setup database
+ cy.setupDB("course-menu", "setup");
+ cy.login();
+
+ // visit the home page
+ cy.visit("/");
+
+ // check that we can access the menu
+ cy.contains(/add course/i).click();
+
+ // check that it redirects to the courses page
+ cy.location("pathname").should("eq", "/courses");
+
+ // check that CS61A is clickable
+ cy.contains(/cs61a/i).click();
+ cy.location("pathname").should("eq", "/courses/1");
+
+ // back to the course menu
+ cy.go("back");
+ cy.location("pathname").should("eq", "/courses");
+
+ // check that CS61B is clickable
+ cy.contains(/cs61b/i).click();
+ cy.location("pathname").should("eq", "/courses/2");
+
+ // back to the course menu
+ cy.go("back");
+ cy.location("pathname").should("eq", "/courses");
+
+ // check that CS61C is clickable
+ cy.contains(/cs61c/i).click();
+ cy.location("pathname").should("eq", "/courses/3");
+
+ // back to the course menu
+ cy.go("back");
+ cy.location("pathname").should("eq", "/courses");
+ });
+
+ describe("should display courses and enrollment times", () => {
+ it("with no priority enrollment", () => {
+ // setup database
+ cy.setupDB("course-menu", "setup");
+ cy.login();
+
+ // visit the courses page
+ cy.visit("/courses");
+
+ // check that CS61A, CS61B, CS61C are all visible
+ cy.contains(/cs61a/i).should("be.visible");
+ cy.contains(/cs61b/i).should("be.visible");
+ cy.contains(/cs61c/i).should("be.visible");
+
+ // check that CS61A and CS61C show in enrollment times, but not CS61B
+ // cs61a: NOW < start < end; too early
+ cy.contains(".enrollment-container", /cs61a/i).should("be.visible");
+ // cs61b: start < NOW < end; valid
+ cy.contains(".enrollment-container", /cs61b/i).should("not.exist");
+ // cs61c: start < end < NOW; too late
+ cy.contains(".enrollment-container", /cs61c/i).should("be.visible");
+ });
+
+ it("with priority enrollment in the past", () => {
+ // setup database with priority enrollment
+ cy.setupDB("course-menu", "setup_priority_enrollment_past");
+ cy.login();
+
+ // visit the courses page
+ cy.visit("/courses");
+
+ // check that CS61A, CS61B, CS61C are all visible
+ cy.contains(/cs61a/i).should("be.visible");
+ cy.contains(/cs61b/i).should("be.visible");
+ cy.contains(/cs61c/i).should("be.visible");
+
+ // check that CS61C show in enrollment times, but not CS61A or CS61B
+ // because priority enrollment should be active for all courses; still too late for CS61C
+ cy.contains(".enrollment-container", /cs61a/i).should("not.exist");
+ cy.contains(".enrollment-container", /cs61b/i).should("not.exist");
+ cy.contains(".enrollment-container", /cs61c/i).should("be.visible");
+
+ // check that priority enrollment shows in enrollment times
+ cy.contains(".enrollment-container", /priority/i).should("be.visible");
+ });
+
+ it("with priority enrollment in the future", () => {
+ // setup database with priority enrollment
+ cy.setupDB("course-menu", "setup_priority_enrollment_future");
+ cy.login();
+
+ // visit the courses page
+ cy.visit("/courses");
+
+ // check that CS61B, CS61C are all visible
+ cy.contains(/cs61a/i).should("be.visible");
+ cy.contains(/cs61b/i).should("be.visible");
+ cy.contains(/cs61c/i).should("be.visible");
+
+ // check that CS61A and CS61C show in enrollment times, but not CS61B
+ // because priority enrollment exists, but is not time yet
+ cy.contains(".enrollment-container", /cs61a/i).should("be.visible");
+ cy.contains(".enrollment-container", /cs61b/i).should("not.exist");
+ cy.contains(".enrollment-container", /cs61c/i).should("be.visible");
+
+ // check that priority enrollment shows in enrollment times
+ cy.contains(".enrollment-container", /priority/i).should("be.visible");
+ });
+ });
+});
diff --git a/cypress/e2e/course/student-course.cy.ts b/cypress/e2e/course/student-course.cy.ts
new file mode 100644
index 00000000..837402d8
--- /dev/null
+++ b/cypress/e2e/course/student-course.cy.ts
@@ -0,0 +1,244 @@
+/**
+ * Student course tests are under the assumption that the layout
+ * stays the same from the coordinator tests.
+ *
+ * These tests only check for student-specific enrollment actions
+ * for the course menus.
+ */
+
+const checkEnrollButtons = (expectDisabled: boolean = false) => {
+ cy.get(".day-btn").should("have.length", 3).should("be.visible");
+
+ cy.get(".day-btn").each($btn => {
+ // go to the section
+ cy.wrap($btn).click();
+
+ if (!$btn.text().match(/th/i)) {
+ // verify enroll button is there
+ cy.get(".section-card").each($card => {
+ cy.wrap($card).within(() => {
+ if (expectDisabled) {
+ cy.get(".section-card-footer")
+ .should("have.length", 1)
+ // this may change if the implementation changes
+ .should("not.have.css", "color", "rgba(0, 0, 0, 0)")
+ .should("have.class", "disabled")
+ // has the correct text
+ .invoke("text")
+ .should("match", /enroll/i);
+ } else {
+ cy.get(".section-card-footer")
+ .should("have.length", 1)
+ // this may change if the implementation changes
+ .should("not.have.css", "color", "rgba(0, 0, 0, 0)")
+ .should("not.have.class", "disabled")
+ // has the correct text
+ .invoke("text")
+ .should("match", /enroll/i);
+ }
+ });
+ });
+
+ // verify no full sections
+ cy.get(".section-card.full").should("not.exist");
+ }
+
+ cy.get("#show-unavailable-toggle").click();
+
+ // verify all full sections have no enroll button
+ cy.get(".section-card.full").each($card => {
+ cy.wrap($card)
+ // this may change if the implementation changes
+ .find(".section-card-footer")
+ .should("have.css", "color", "rgba(0, 0, 0, 0)");
+ });
+
+ // reset for next check
+ cy.get("#show-unavailable-toggle").click();
+ });
+};
+
+const checkEnrollAction = () => {
+ cy.get(".section-card:not(.full) .section-card-footer").first().click();
+
+ // enrollment should be successful
+ cy.get(".modal-contents")
+ .should("be.visible")
+ .invoke("text")
+ .should("match", /successfully enrolled/i);
+
+ // click on the ok button
+ cy.contains(".modal-contents .modal-btn", /ok/i)
+ .click()
+ // modal should disappear
+ .should("not.exist");
+
+ // should be brought to the home page
+ cy.location("pathname").should("eq", "/");
+
+ // home page should now have a card
+ cy.get(".course-card")
+ .should("have.length", 1)
+ .within(() => {
+ // enrolled as a student
+ cy.contains(".relation-label", /student/i).should("be.visible");
+ // for cs61a
+ cy.contains(".course-card-name", /cs61a/i).should("be.visible");
+ });
+};
+
+const checkFailedEnrollAction = () => {
+ // iterate through each day
+ cy.get(".day-btn").each($btn => {
+ cy.wrap($btn).click();
+
+ if ($btn.text().match(/th/i)) {
+ // nothing to check on thursday; no sections with capacity
+ return;
+ }
+ cy.get(".section-card").each($card => {
+ // shouldn't be able to click on enroll
+ cy.wrap($card)
+ .contains(/enroll/i)
+ .within($enroll => {
+ // pointer events should be disabled
+ cy.wrap($enroll).should("have.css", "pointer-events", "none");
+
+ // force a click on enroll button anyways
+ // ignore waiting to be actionable
+ cy.wrap($enroll).click({ force: true });
+ });
+
+ // should open modal saying enrollment failed
+ cy.get(".modal-contents")
+ .should("be.visible")
+ .invoke("text")
+ .should("match", /enrollment failed/i);
+
+ // dismiss modal
+ cy.contains(".modal-contents .modal-btn", /ok/i).click().should("not.exist");
+ });
+ });
+
+ // keep track of profiles requests
+ cy.intercept("/api/profiles").as("profiles");
+
+ // go back to home page
+ cy.visit("/");
+
+ // wait for all profiles to load
+ cy.wait("@profiles");
+
+ // should not see any cards
+ cy.get(".course-card").should("not.exist");
+};
+
+before(() => {
+ // initialize the database and cache
+ cy.initDB();
+});
+
+describe("student course view", () => {
+ context("with no priority enrollment", () => {
+ context("with the course open", () => {
+ it("should see enroll button for all sections", () => {
+ // setup
+ cy.setupDB("coordinator-student-course", "student_setup_open");
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkEnrollButtons();
+ });
+
+ it("should be able to enroll in a section", () => {
+ // setup (mutates the database)
+ cy.setupDB("coordinator-student-course", "student_setup_open", { mutate: true });
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkEnrollAction();
+ });
+ });
+
+ context("with the course closed", () => {
+ it("should see disabled enroll button and enrollment time for all sections", () => {
+ cy.setupDB("coordinator-student-course", "student_setup_closed");
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkEnrollButtons(true);
+
+ // iterate through each day
+ cy.get(".day-btn").each($btn => {
+ cy.wrap($btn).click();
+
+ // should display no matter what day is selected
+ cy.get("#course-enrollment-open-status")
+ .should("be.visible")
+ .invoke("text")
+ .should("match", /^enrollment opens/i);
+ });
+ });
+
+ it("should not be able to enroll in any section", () => {
+ // if fails, could mutate the database
+ cy.setupDB("coordinator-student-course", "student_setup_closed", { mutate: true });
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkFailedEnrollAction();
+ });
+ });
+ });
+
+ context("with priority enrollment", () => {
+ context("with the course open", () => {
+ it("should see enroll button for any section", () => {
+ cy.setupDB("coordinator-student-course", "student_setup_open_priority");
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkEnrollButtons();
+ });
+
+ it("should be able to enroll in a section", () => {
+ // will mutate the database
+ cy.setupDB("coordinator-student-course", "student_setup_open_priority", { mutate: true });
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkEnrollAction();
+ });
+ });
+
+ context("with the course closed", () => {
+ it("should see disabled enroll button and priority enrollment text for all sections", () => {
+ cy.setupDB("coordinator-student-course", "student_setup_closed_priority");
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkEnrollButtons(true);
+
+ // iterate through each day
+ cy.get(".day-btn").each($btn => {
+ cy.wrap($btn).click();
+
+ // should display no matter what day is selected
+ cy.get("#course-enrollment-open-status")
+ .should("be.visible")
+ .invoke("text")
+ .should("match", /^priority enrollment opens/i);
+ });
+ });
+
+ it("should not be able to enroll in any section", () => {
+ // if fails, could mutate the database
+ cy.setupDB("coordinator-student-course", "student_setup_closed_priority", { mutate: true });
+ cy.login();
+ cy.visit("/courses/1");
+
+ checkFailedEnrollAction();
+ });
+ });
+ });
+});
diff --git a/cypress/e2e/login.cy.ts b/cypress/e2e/login.cy.ts
new file mode 100644
index 00000000..c8d34d12
--- /dev/null
+++ b/cypress/e2e/login.cy.ts
@@ -0,0 +1,15 @@
+before(() => {
+ cy.initDB();
+});
+
+describe("login", () => {
+ it("should display home page after login", () => {
+ cy.setupDB("login", "setup");
+
+ cy.login();
+
+ // check that we can access the homepage
+ cy.visit("/");
+ cy.get("h3.page-title").should("contain", "My courses");
+ });
+});
diff --git a/cypress/e2e/section/mentor-section.cy.ts b/cypress/e2e/section/mentor-section.cy.ts
new file mode 100644
index 00000000..4c29fb7f
--- /dev/null
+++ b/cypress/e2e/section/mentor-section.cy.ts
@@ -0,0 +1,658 @@
+before(() => {
+ cy.initDB();
+});
+
+const STUDENT_LIST = [/A Student/i, /B Student/i, /C Student/i, /D Student/i];
+
+/**
+ * tests for accessing and viewing section details
+ */
+describe("section details accessibility", () => {
+ it("should be able to navigate to and view section details", () => {
+ cy.setupDB("mentor-section", "setup_mentor_section");
+ cy.login();
+ cy.visit("/");
+
+ cy.contains(".course-card .relation-label", /mentor/i)
+ .should("be.visible")
+ .parent()
+ .click();
+
+ cy.location("pathname").should("eq", "/sections/1");
+
+ cy.contains(".section-detail-header-title", /cs61a/i).should("be.visible");
+ cy.contains(".relation-label", /mentor/i).should("be.visible");
+
+ // title
+ cy.contains(".section-detail-header-title", /cs61a/i).should("be.visible");
+ cy.contains(".relation-label", /mentor/i).should("be.visible");
+
+ // students
+ cy.get(".section-detail-info-card.students")
+ .should("be.visible")
+ .find(".section-detail-info-card-contents")
+ .should("be.visible")
+ // 4 students enrolled
+ .find(".student-info")
+ .should("have.length", 4);
+
+ // time and location cards
+ cy.get(".section-detail-info-card.time-and-location-1").should("be.visible");
+ cy.get(".section-detail-info-card.time-and-location-2").should("be.visible");
+
+ // meta card
+ cy.get(".section-detail-info-card.meta")
+ .should("be.visible")
+ .find(".section-detail-info-card-contents")
+ .within(() => {
+ cy.contains(".meta-field", /capacity/i)
+ .parent()
+ .invoke("text")
+ .should("match", /5$/i);
+ cy.contains(".meta-field", /description/i)
+ .parent()
+ .invoke("text")
+ .should("match", /test section$/i);
+ });
+
+ // go to roster tab
+ cy.contains("#section-detail-sidebar a", /roster/i).click();
+ cy.location("pathname").should("eq", "/sections/1/roster");
+
+ cy.contains(".section-detail-page-title", /roster/i).should("be.visible");
+
+ const expectedTable = [
+ [/A Student/i, /A_student@berkeley.edu/i],
+ [/B Student/i, /B_student@berkeley.edu/i],
+ [/C Student/i, /C_student@berkeley.edu/i],
+ [/D Student/i, /D_student@berkeley.edu/i]
+ ];
+ cy.get("table.standalone-table tbody tr")
+ .should("have.length", 4)
+ .each(($row, rowIdx) => {
+ cy.wrap($row)
+ .find("td")
+ .should("have.length", 2)
+ .each(($cell, cellIdx) => {
+ expect($cell.text()).to.match(expectedTable[rowIdx][cellIdx]);
+ });
+ });
+ });
+});
+
+/**
+ * tests for manipulating attendances
+ */
+describe("attendances", () => {
+ it("should be able to navigate to and view section attendances", () => {
+ cy.setupDB("mentor-section", "setup_mentor_section");
+ cy.login();
+ cy.visit("/sections/1");
+
+ // go to attendances tab
+ cy.contains("#section-detail-sidebar a", /attendance/i).click();
+
+ cy.location("pathname").should("eq", "/sections/1/attendance");
+
+ cy.contains(".section-detail-page-title", /attendance/i).should("be.visible");
+
+ // date tabs
+ cy.get("#attendance-date-tabs-container")
+ .children()
+ .should("have.length", 2)
+ // click second (inactive) tab
+ .last()
+ .should("not.have.class", "active")
+ .click()
+ .should("have.class", "active");
+
+ // attendances in the second tab should all be present
+ cy.get("#mentor-attendance-table select")
+ .should("have.length", 4)
+ .each($select => {
+ expect($select.val()).to.be.eq("PR");
+ });
+ });
+
+ context("functional checks", () => {
+ beforeEach(() => {
+ cy.setupDB("mentor-section", "setup_mentor_section", { mutate: true });
+ cy.login();
+ });
+
+ it("should be able to mark all students as present", () => {
+ cy.visit("/sections/1/attendance");
+ cy.intercept({ method: "GET", url: "/api/sections/1/attendance" }).as("section-attendance");
+ cy.intercept({ method: "PUT", url: "/api/students/*/attendances" }).as("student-attendance");
+
+ // all attendances should start blank
+ cy.get("#mentor-attendance-table select")
+ .should("have.length", 4)
+ .each($select => {
+ expect($select.val()).to.be.null;
+ });
+
+ cy.get(".mark-all-present-btn").click();
+
+ // all attendances should be marked as present
+ cy.get("#mentor-attendance-table select")
+ .should("have.length", 4)
+ .each($select => {
+ expect($select.val()).to.be.eq("PR");
+ });
+
+ // save attendance
+ cy.get(".save-attendance-btn").click();
+ cy.wait(["@student-attendance", "@student-attendance", "@student-attendance", "@student-attendance"]);
+
+ // reload
+ cy.reload();
+ cy.wait("@section-attendance");
+
+ // all attendances should still be marked as present
+ cy.get("#mentor-attendance-table select")
+ .should("have.length", 4)
+ .each($select => {
+ expect($select.val()).to.be.eq("PR");
+ });
+ });
+
+ it("should be able to mark a single student as absent", () => {
+ cy.visit("/sections/1/attendance");
+ cy.intercept("/api/students/*/attendances").as("student-attendance");
+ cy.intercept("/api/sections/1/attendance").as("section-attendance");
+
+ // all attendances should start blank
+ cy.get("#mentor-attendance-table select")
+ .should("have.length", 4)
+ .each($select => {
+ expect($select.val()).to.be.null;
+ });
+
+ cy.get("#mentor-attendance-table select").first().select("EX");
+
+ // first attendnace should be excused, rest should be blank
+ cy.get("#mentor-attendance-table select").each(($select, idx) => {
+ if (idx === 0) {
+ expect($select.val()).to.be.eq("EX");
+ } else {
+ expect($select.val()).to.be.null;
+ }
+ });
+
+ // save and wait for at least one request
+ cy.get(".save-attendance-btn").click();
+ cy.wait("@student-attendance");
+
+ // reload
+ cy.reload();
+ cy.wait("@section-attendance");
+
+ // first attendance should be excused, rest should be blank
+ cy.get("#mentor-attendance-table select").each(($select, idx) => {
+ if (idx === 0) {
+ expect($select.val()).to.be.eq("EX");
+ } else {
+ expect($select.val()).to.be.null;
+ }
+ });
+ });
+ });
+});
+
+/**
+ * tests for modifying students in the section
+ */
+describe("modifying students", () => {
+ const _commonSetup = () => {
+ cy.login();
+ cy.visit("/sections/1");
+
+ cy.intercept({ method: "PUT", url: "/api/sections/1/students" }).as("add-student");
+ cy.intercept({ method: "GET", url: "/api/sections/1/students" }).as("section-students");
+ cy.intercept({ method: "PATCH", url: "/api/students/*/drop" }).as("drop-student");
+ };
+
+ const setupWithMutate = () => {
+ cy.setupDB("mentor-section", "setup_multiple_mentor_sections", { mutate: true });
+ _commonSetup();
+ };
+
+ const setupFullSection = () => {
+ cy.setupDB("mentor-section", "setup_full_section", { mutate: true });
+ _commonSetup();
+ };
+
+ context("valid operations", () => {
+ it("should allow adding new student to section", () => {
+ setupWithMutate();
+
+ cy.wait("@section-students");
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal").within(() => {
+ // input new student email
+ cy.get(".coordinator-email-input").type("testuser1@berkeley.edu");
+
+ // submit
+ cy.get(".coordinator-email-input-submit").click();
+ });
+
+ // wait for request to finish
+ cy.wait("@add-student").its("response.statusCode").should("eq", 200);
+ cy.wait("@section-students");
+
+ // modal should be closed
+ cy.get(".coordinator-add-student-modal").should("not.exist");
+
+ // student should appear in the roster
+ cy.contains("#students-table span.student-info", /test user 1/i).should("be.visible");
+
+ // reload page
+ cy.reload();
+ cy.wait("@section-students");
+
+ // student should still appear in the roster
+ cy.contains("#students-table span.student-info", /test user 1/i).should("be.visible");
+ });
+
+ it("should allow adding new student associated with a new user", () => {
+ setupWithMutate();
+
+ cy.wait("@section-students");
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal").within(() => {
+ // input new student email
+ cy.get(".coordinator-email-input").type("newuser@berkeley.edu");
+
+ // submit
+ cy.get(".coordinator-email-input-submit").click();
+ });
+
+ // wait for request to finish
+ cy.wait("@add-student").its("response.statusCode").should("eq", 200);
+ cy.wait("@section-students");
+
+ // modal should be closed
+ cy.get(".coordinator-add-student-modal").should("not.exist");
+
+ // student should appear in the roster
+ cy.contains("#students-table span.student-info", /newuser@berkeley\.edu/i).should("be.visible");
+
+ // reload page
+ cy.reload();
+ cy.wait("@section-students");
+
+ // student should still appear in the roster
+ cy.contains("#students-table span.student-info", /newuser@berkeley\.edu/i).should("be.visible");
+ });
+
+ it("should allow dropping existing student", () => {
+ setupWithMutate();
+
+ cy.wait("@section-students");
+
+ // drop student
+ cy.get("#students-table .student-dropper")
+ .first()
+ .parent() // get first table row
+ .within(() => {
+ cy.get(".student-info")
+ .invoke("text")
+ .should("match", /A Student/i);
+
+ cy.get(".student-dropper").click();
+ });
+
+ // perform the drop
+ cy.get(".studentDropper").within(() => {
+ cy.get("input#drop").click();
+ cy.get(".studentDropperSubmit").click();
+ });
+
+ cy.wait("@drop-student").its("response.statusCode").should("eq", 204);
+ cy.wait("@section-students");
+
+ // modal should disappear
+ cy.get(".studentDropper").should("not.exist");
+ // student should not appear in the list
+ cy.contains("#students-table .student-info", /A Student/i).should("not.exist");
+ });
+
+ it("should do nothing if no emails are given", () => {
+ // potential mutation if this fails
+ setupWithMutate();
+
+ cy.wait("@section-students");
+
+ // expected list of students (in order)
+ cy.get("#students-table span.student-info")
+ .should("have.length", 4)
+ .each(($text, idx) => {
+ expect($text.text()).to.match(STUDENT_LIST[idx]);
+ });
+
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal").within(() => {
+ cy.get(".coordinator-email-input-item").should("have.length", 1).get("[title='Remove']").click();
+ cy.get(".coordinator-email-input-submit").click();
+ });
+
+ cy.get(".coordinator-add-student-modal").should("not.exist");
+
+ // should have the same list of students
+ cy.get("#students-table span.student-info")
+ .should("have.length", 4)
+ .each(($text, idx) => {
+ expect($text.text()).to.match(STUDENT_LIST[idx]);
+ });
+ });
+ });
+ context("invalid operations", () => {
+ it("should retry when adding mentor for another section", () => {
+ // possible to mutate if fails
+ setupWithMutate();
+ const USERNAME = "user1@berkeley.edu";
+
+ cy.wait("@section-students");
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal")
+ .within(() => {
+ cy.get(".coordinator-email-input").type(USERNAME);
+ cy.get(".coordinator-email-input-submit").click();
+
+ // wait for request; should fail
+ cy.wait("@add-student").its("response.statusCode").should("eq", 422);
+
+ cy.contains(".coordinator-email-response-container", /section conflict/i)
+ .within(() => {
+ // should display section conflict
+ cy.contains(".coordinator-email-response-status-conflict", /section conflict/i).should("be.visible");
+
+ cy.contains(".coordinator-email-response-item", USERNAME)
+ .within(() => {
+ // check text objects
+ cy.contains("span", USERNAME).should("be.visible");
+ cy.contains("div", /User is already a mentor for the course/i).should("be.visible");
+ cy.get("input[type='checkbox'][value='DROP']").should("have.length", 1).should("be.disabled");
+
+ // remove email
+ cy.get("span.inline-plus-sign").click().should("not.exist");
+ })
+ .should("not.exist"); // should disappear after click
+ })
+ .should("not.exist"); // should disappear after click
+
+ cy.contains(".coordinator-email-input-submit", /retry/i).click();
+ // no request, so no wait
+ })
+ .should("not.exist"); // should disappear after click
+
+ // students should stay the same
+ cy.get("#students-table span.student-info")
+ .should("have.length", 4)
+ .each(($text, idx) => {
+ expect($text.text()).to.match(STUDENT_LIST[idx]);
+ });
+ });
+
+ it("should retry when adding student in another section", () => {
+ setupWithMutate();
+ const USERNAME = "user2@berkeley.edu";
+
+ cy.wait("@section-students");
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal")
+ .within(() => {
+ cy.get(".coordinator-email-input").type(USERNAME);
+ cy.get(".coordinator-email-input-submit").click();
+
+ // wait for request; should fail
+ cy.wait("@add-student").its("response.statusCode").should("eq", 422);
+
+ cy.contains(".coordinator-email-response-container", /section conflict/i).within(() => {
+ // should display section conflict
+ cy.contains(".coordinator-email-response-status-conflict", /section conflict/i).should("be.visible");
+
+ cy.contains(".coordinator-email-response-item", USERNAME).within(() => {
+ // check text objects
+ cy.contains("span", USERNAME).should("be.visible");
+ cy.contains("div", /conflict: user one/i)
+ .should("be.visible")
+ .find("a")
+ .invoke("attr", "href")
+ .should("eq", "/sections/2");
+
+ // drop student from other section
+ cy.get("input[type='checkbox'][value='DROP']").should("have.length", 1).should("not.be.disabled").click();
+ });
+ });
+
+ cy.contains(".coordinator-email-input-submit", /retry/i).click();
+ cy.wait("@add-student").its("response.statusCode").should("eq", 200);
+ })
+ .should("not.exist"); // should disappear after click
+
+ cy.wait("@section-students");
+
+ // one more student should appear
+ cy.get("#students-table span.student-info")
+ .should("have.length", 5)
+ .each(($text, idx) => {
+ if (idx == 4) {
+ // should be at the end
+ expect($text.text()).to.match(/User Two/i);
+ } else {
+ expect($text.text()).to.match(STUDENT_LIST[idx]);
+ }
+ });
+ });
+
+ it("should retry when adding banned student", () => {
+ setupWithMutate();
+ const USERNAME = "banned_student@berkeley.edu";
+
+ cy.wait("@section-students");
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal")
+ .within(() => {
+ cy.get(".coordinator-email-input").type(USERNAME);
+ cy.get(".coordinator-email-input-submit").click();
+
+ // wait for request; should fail
+ cy.wait("@add-student").its("response.statusCode").should("eq", 422);
+
+ cy.contains(".coordinator-email-response-container", /student banned/i).within(() => {
+ cy.contains(".coordinator-email-response-status-banned", /student banned/i).should("be.visible");
+
+ cy.contains(".coordinator-email-response-item", USERNAME).within(() => {
+ // get actual text object
+ cy.contains("span", USERNAME).should("be.visible");
+ // unban and enroll student
+ cy.get("input[type='radio'][value='UNBAN_ENROLL']")
+ .should("have.length", 1)
+ .should("not.be.disabled")
+ .click();
+ });
+ });
+
+ cy.contains(".coordinator-email-input-submit", /retry/i).click();
+ cy.wait("@add-student").its("response.statusCode").should("eq", 200);
+ })
+ .should("not.exist"); // should disappear after click
+
+ cy.wait("@section-students");
+
+ // one more student should appear
+ const expected_list = [...STUDENT_LIST.slice(0, 2), /banned student/i, ...STUDENT_LIST.slice(2)];
+ cy.get("#students-table span.student-info")
+ .should("have.length", 5)
+ .each(($text, idx) => {
+ expect($text.text()).to.match(expected_list[idx]);
+ });
+ });
+
+ it("should retry when section is at capacity", () => {
+ setupFullSection();
+
+ cy.wait("@section-students");
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal")
+ .within(() => {
+ cy.get(".coordinator-email-input").type("testuser1@berkeley.edu");
+ cy.get(".coordinator-email-input-submit").click();
+
+ // wait for request; should fail
+ cy.wait("@add-student").its("response.statusCode").should("eq", 422);
+
+ cy.contains(".coordinator-email-response-capacity-container", /section capacity exceeded/i).within(() => {
+ // should display capacity exceeded
+ cy.contains(".coordinator-email-response-capacity", /section capacity exceeded/i).should("be.visible");
+
+ cy.get("input[type='radio'][value='EXPAND']").click();
+ });
+
+ cy.contains(".coordinator-email-input-submit", /retry/i).click();
+ cy.wait("@add-student").its("response.statusCode").should("eq", 200);
+ })
+ .should("not.exist");
+
+ cy.wait("@section-students");
+
+ const expected_list = [...STUDENT_LIST, /E Student/i, /Test User 1/i];
+ cy.get("#students-table span.student-info")
+ .should("have.length", 6)
+ .each(($text, idx) => {
+ expect($text.text()).to.match(expected_list[idx]);
+ });
+
+ // meta card should have new capacity
+ cy.get(".section-detail-info-card.meta")
+ .should("be.visible")
+ .find(".section-detail-info-card-contents")
+ .within(() => {
+ cy.contains(".meta-field", /capacity/i)
+ .parent()
+ .invoke("text")
+ .should("match", /6$/i);
+ });
+ });
+
+ it("should retry with multiple kinds of errors", () => {
+ setupWithMutate();
+
+ cy.wait("@section-students");
+ cy.get(".coordinator-email-modal-button").click();
+
+ cy.get(".coordinator-add-student-modal")
+ .within(() => {
+ // valid user
+ cy.get(".coordinator-email-input").last().type("testuser1@berkeley.edu");
+ cy.contains(".coordinator-email-input-add", /add email/i)
+ .focus()
+ .click();
+ // mentor for another section
+ cy.get(".coordinator-email-input").last().type("user1@berkeley.edu");
+ cy.contains(".coordinator-email-input-add", /add email/i).click();
+ // conflicting section
+ cy.get(".coordinator-email-input").last().type("user2@berkeley.edu");
+ cy.contains(".coordinator-email-input-add", /add email/i).click();
+ // banned user
+ cy.get(".coordinator-email-input").last().type("banned_student@berkeley.edu");
+
+ // submit and wait for request; should fail
+ cy.get(".coordinator-email-input-submit").click();
+ cy.wait("@add-student").its("response.statusCode").should("eq", 422);
+
+ cy.contains(".coordinator-email-response-container", /section conflict/i).within(() => {
+ // should display section conflict
+ cy.contains(".coordinator-email-response-status-conflict", /section conflict/i).should("be.visible");
+
+ // conflicting section
+ cy.contains(".coordinator-email-response-item", "user1@berkeley.edu").within(() => {
+ // check text objects
+ cy.contains("span", "user1@berkeley.edu").should("be.visible");
+ cy.contains("div", /User is already a mentor for the course/i).should("be.visible");
+ cy.get("input[type='checkbox'][value='DROP']").should("have.length", 1).should("be.disabled");
+
+ // remove email
+ cy.get("span.inline-plus-sign").click().should("not.exist");
+ });
+
+ // mentor for another section
+ cy.contains(".coordinator-email-response-item", "user2@berkeley.edu").within(() => {
+ // get actual text object
+ cy.contains("span", "user2@berkeley.edu").should("be.visible");
+ // check conflicting section link
+ cy.contains("div", /conflict: user one/i)
+ .should("be.visible")
+ .find("a")
+ .invoke("attr", "href")
+ .should("eq", "/sections/2");
+
+ // drop student from other section
+ cy.get("input[type='checkbox'][value='DROP']").should("have.length", 1).should("not.be.disabled").click();
+ });
+ });
+
+ cy.contains(".coordinator-email-response-container", /student banned/i).within(() => {
+ // should display section conflict
+ cy.contains(".coordinator-email-response-status-banned", /student banned/i).should("be.visible");
+
+ cy.contains(".coordinator-email-response-item", "banned_student@berkeley.edu").within(() => {
+ // get actual text object
+ cy.contains("span", "banned_student@berkeley.edu").should("be.visible");
+ // unban and enroll student
+ cy.get("input[type='radio'][value='UNBAN_ENROLL']")
+ .should("have.length", 1)
+ .should("not.be.disabled")
+ .click();
+ });
+ });
+
+ // valid user
+ cy.contains(".coordinator-email-response-container", /ok/i).within(() => {
+ cy.contains(".coordinator-email-response-status-ok", /ok/i).should("be.visible");
+ // not visible but should have visible text
+ cy.contains(".coordinator-email-response-item span", "testuser1@berkeley.edu").should("exist");
+ });
+
+ cy.contains(".coordinator-email-response-capacity-container", /section capacity exceeded/i).within(() => {
+ // should display capacity exceeded
+ cy.contains(".coordinator-email-response-capacity", /section capacity exceeded/i).should("be.visible");
+
+ cy.get("input[type='radio'][value='EXPAND']").click();
+ });
+
+ // submit form
+ cy.get(".coordinator-email-input-submit").click();
+ cy.wait("@add-student");
+ })
+ .should("not.exist");
+
+ cy.wait("@section-students");
+
+ // check student list
+ const expected_list = [
+ /A Student/i,
+ /B Student/i,
+ /banned student/i,
+ /C Student/i,
+ /D Student/i,
+ /Test User 1/i,
+ /User Two/i
+ ];
+ cy.get("#students-table span.student-info")
+ .should("have.length", 7)
+ .each(($text, idx) => {
+ expect($text.text()).to.match(expected_list[idx]);
+ });
+ });
+ });
+});
diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts
new file mode 100644
index 00000000..0dd586a6
--- /dev/null
+++ b/cypress/support/commands.ts
@@ -0,0 +1,70 @@
+///
+
+/**
+ * Headless login
+ */
+Cypress.Commands.add("login", () => {
+ cy.request("/admin/login/")
+ .its("headers")
+ .then(headers => {
+ const csrfToken = headers["set-cookie"][0].match(/csrftoken=(.*?);/)[1];
+ cy.setCookie("csrftoken", csrfToken);
+ cy.request({
+ method: "POST",
+ url: "/admin/login/",
+ form: true,
+ body: {
+ username: "demo_user",
+ password: "pass",
+ csrfmiddlewaretoken: csrfToken
+ }
+ });
+ });
+});
+
+interface SetupDBOptions {
+ force?: boolean;
+ mutate?: boolean;
+}
+
+/**
+ * Setup the Django database for use in Cypress tests
+ */
+Cypress.Commands.add(
+ "setupDB",
+ (script_path: string, func_name: string, options: SetupDBOptions = { force: false, mutate: false }) => {
+ // validate arguments
+ expect(script_path.match(/[a-zA-Z0-9_\/\.\-]/)).to.not.be.null;
+ expect(func_name.match(/[a-zA-Z0-9_]/)).to.not.be.null;
+
+ // run setup script
+ let command = `python3 cypress/db/_setup.py "${script_path}" "${func_name}"`;
+ if (options.force) {
+ command += " --force";
+ }
+ if (options.mutate) {
+ command += " --mutate";
+ }
+ cy._exec(command);
+ }
+);
+
+/**
+ * Initialize the Django database and cache
+ */
+Cypress.Commands.add("initDB", () => {
+ cy._exec("python3 cypress/db/_setup.py --init");
+});
+
+/**
+ * Wrapper wround cy.exec that does not truncate output
+ */
+Cypress.Commands.add("_exec", command => {
+ cy.exec(command, { failOnNonZeroExit: false }).then(result => {
+ if (result.code) {
+ throw new Error(
+ `Execution of ${command} failed\nExit code: ${result.code}\nStdout:\n${result.stdout}\nStderr:\n${result.stderr}`
+ );
+ }
+ });
+});
diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts
new file mode 100644
index 00000000..ed5730de
--- /dev/null
+++ b/cypress/support/e2e.ts
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/e2e.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/cypress/support/index.d.ts b/cypress/support/index.d.ts
new file mode 100644
index 00000000..dd2d2e9c
--- /dev/null
+++ b/cypress/support/index.d.ts
@@ -0,0 +1,13 @@
+interface SetupDBOptions {
+ force?: boolean;
+ mutate?: boolean;
+}
+
+declare namespace Cypress {
+ interface Chainable {
+ login(): Chainable;
+ setupDB(script_name: string, func_name: string, options?: SetupDBOptions): Chainable;
+ initDB(): Chainable;
+ _exec(command: string): Chainable;
+ }
+}
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
new file mode 100644
index 00000000..11fd6929
--- /dev/null
+++ b/cypress/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "baseUrl": "../node_modules",
+ "types": ["cypress"],
+ "target": "es2019"
+ },
+ "include": ["**/*.*"]
+}
diff --git a/package-lock.json b/package-lock.json
index fd63c493..a9376d34 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -45,8 +45,10 @@
"babel-polyfill": "^6.26.0",
"css-loader": "^6.2.0",
"csso-cli": "^3.0.0",
+ "cypress": "^12.2.0",
"eslint": "^8.27.0",
"eslint-config-prettier": "^7.2.0",
+ "eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-react": "^7.31.10",
"eslint-plugin-react-hooks": "^4.6.0",
"jest": "^28.1.1",
@@ -1901,6 +1903,91 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/@cypress/request": {
+ "version": "2.88.10",
+ "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz",
+ "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==",
+ "dev": true,
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "http-signature": "~1.3.6",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^8.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@cypress/request/node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/@cypress/request/node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/@cypress/xvfb": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
+ "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^3.1.0",
+ "lodash.once": "^4.1.1"
+ }
+ },
+ "node_modules/@cypress/xvfb/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
@@ -4199,6 +4286,18 @@
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"dev": true
},
+ "node_modules/@types/sinonjs__fake-timers": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz",
+ "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==",
+ "dev": true
+ },
+ "node_modules/@types/sizzle": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
+ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
+ "dev": true
+ },
"node_modules/@types/stack-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
@@ -4233,6 +4332,16 @@
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
},
+ "node_modules/@types/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
@@ -4726,6 +4835,19 @@
"node": ">= 6.0.0"
}
},
+ "node_modules/aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "dependencies": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -4751,6 +4873,15 @@
"ajv": "^6.9.1"
}
},
+ "node_modules/ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
@@ -4812,6 +4943,26 @@
"node": ">= 8"
}
},
+ "node_modules/arch": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
+ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -4889,12 +5040,54 @@
"get-intrinsic": "^1.1.3"
}
},
+ "node_modules/asn1": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
+ "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+ "dev": true
+ },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
},
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
@@ -4907,6 +5100,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
+ "dev": true
+ },
"node_modules/babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -5372,6 +5580,35 @@
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
+ "dev": true,
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -5390,6 +5627,18 @@
"node": ">=8"
}
},
+ "node_modules/blob-util": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz",
+ "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==",
+ "dev": true
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -5455,12 +5704,54 @@
"node-int64": "^0.4.0"
}
},
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
+ "node_modules/cachedir": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz",
+ "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -5508,6 +5799,12 @@
}
]
},
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
+ "dev": true
+ },
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -5531,6 +5828,15 @@
"node": ">=10"
}
},
+ "node_modules/check-more-types": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
+ "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/chokidar": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
@@ -5622,6 +5928,58 @@
"node": ">=0.8.0"
}
},
+ "node_modules/clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-table3": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
+ "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": "10.* || >= 12.*"
+ },
+ "optionalDependencies": {
+ "@colors/colors": "1.5.0"
+ }
+ },
+ "node_modules/cli-truncate": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+ "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "dev": true,
+ "dependencies": {
+ "slice-ansi": "^3.0.0",
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -5723,6 +6081,15 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
+ "node_modules/common-tags": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
+ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -5780,6 +6147,12 @@
"url": "https://opencollective.com/core-js"
}
},
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
+ "dev": true
+ },
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -5969,44 +6342,275 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
- "node_modules/data-urls": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
- "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
- "dev": true,
- "dependencies": {
- "abab": "^2.0.6",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^11.0.0"
+ "node_modules/cypress": {
+ "version": "12.2.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.2.0.tgz",
+ "integrity": "sha512-kvl95ri95KK8mAy++tEU/wUgzAOMiIciZSL97LQvnOinb532m7dGvwN0mDSIGbOd71RREtmT9o4h088RjK5pKw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "@cypress/request": "^2.88.10",
+ "@cypress/xvfb": "^1.2.4",
+ "@types/node": "^14.14.31",
+ "@types/sinonjs__fake-timers": "8.1.1",
+ "@types/sizzle": "^2.3.2",
+ "arch": "^2.2.0",
+ "blob-util": "^2.0.2",
+ "bluebird": "^3.7.2",
+ "buffer": "^5.6.0",
+ "cachedir": "^2.3.0",
+ "chalk": "^4.1.0",
+ "check-more-types": "^2.24.0",
+ "cli-cursor": "^3.1.0",
+ "cli-table3": "~0.6.1",
+ "commander": "^5.1.0",
+ "common-tags": "^1.8.0",
+ "dayjs": "^1.10.4",
+ "debug": "^4.3.2",
+ "enquirer": "^2.3.6",
+ "eventemitter2": "6.4.7",
+ "execa": "4.1.0",
+ "executable": "^4.1.1",
+ "extract-zip": "2.0.1",
+ "figures": "^3.2.0",
+ "fs-extra": "^9.1.0",
+ "getos": "^3.2.1",
+ "is-ci": "^3.0.0",
+ "is-installed-globally": "~0.4.0",
+ "lazy-ass": "^1.6.0",
+ "listr2": "^3.8.3",
+ "lodash": "^4.17.21",
+ "log-symbols": "^4.0.0",
+ "minimist": "^1.2.6",
+ "ospath": "^1.2.2",
+ "pretty-bytes": "^5.6.0",
+ "proxy-from-env": "1.0.0",
+ "request-progress": "^3.0.0",
+ "semver": "^7.3.2",
+ "supports-color": "^8.1.1",
+ "tmp": "~0.2.1",
+ "untildify": "^4.0.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "cypress": "bin/cypress"
},
"engines": {
- "node": ">=12"
+ "node": "^14.0.0 || ^16.0.0 || >=18.0.0"
}
},
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "node_modules/cypress/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
- "ms": "2.1.2"
+ "color-convert": "^2.0.1"
},
"engines": {
- "node": ">=6.0"
+ "node": ">=8"
},
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/decimal.js": {
- "version": "10.4.2",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz",
- "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==",
- "dev": true
- },
- "node_modules/dedent": {
+ "node_modules/cypress/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/cypress/node_modules/chalk/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cypress/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/cypress/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/cypress/node_modules/commander": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/cypress/node_modules/execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/cypress/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cypress/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cypress/node_modules/human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.12.0"
+ }
+ },
+ "node_modules/cypress/node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/cypress/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/data-urls": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
+ "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
+ "dev": true,
+ "dependencies": {
+ "abab": "^2.0.6",
+ "whatwg-mimetype": "^3.0.0",
+ "whatwg-url": "^11.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz",
+ "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==",
+ "dev": true
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decimal.js": {
+ "version": "10.4.2",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz",
+ "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==",
+ "dev": true
+ },
+ "node_modules/dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
"integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
@@ -6201,6 +6805,16 @@
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
+ "dev": true,
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.284",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
@@ -6234,6 +6848,15 @@
"node": ">= 4"
}
},
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
@@ -6247,6 +6870,18 @@
"node": ">=10.13.0"
}
},
+ "node_modules/enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
"node_modules/entities": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
@@ -6537,6 +7172,18 @@
"eslint": ">=7.0.0"
}
},
+ "node_modules/eslint-plugin-cypress": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz",
+ "integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==",
+ "dev": true,
+ "dependencies": {
+ "globals": "^11.12.0"
+ },
+ "peerDependencies": {
+ "eslint": ">= 3.2.1"
+ }
+ },
"node_modules/eslint-plugin-react": {
"version": "7.31.11",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz",
@@ -6995,6 +7642,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/eventemitter2": {
+ "version": "6.4.7",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
+ "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
+ "dev": true
+ },
"node_modules/events": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
@@ -7027,6 +7680,18 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
+ "node_modules/executable": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
+ "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -7061,6 +7726,56 @@
"node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0"
}
},
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
+ "node_modules/extract-zip/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ]
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -7119,6 +7834,30 @@
"bser": "2.1.1"
}
},
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dev": true,
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -7201,6 +7940,15 @@
"is-callable": "^1.1.3"
}
},
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@@ -7215,6 +7963,30 @@
"node": ">= 6"
}
},
+ "node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/fs-extra/node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -7323,6 +8095,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/getos": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
+ "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==",
+ "dev": true,
+ "dependencies": {
+ "async": "^3.2.0"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
"node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
@@ -7361,6 +8151,21 @@
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"dev": true
},
+ "node_modules/global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "dev": true,
+ "dependencies": {
+ "ini": "2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -7535,6 +8340,20 @@
"node": ">= 6"
}
},
+ "node_modules/http-signature": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz",
+ "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^2.0.2",
+ "sshpk": "^1.14.1"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -7581,6 +8400,26 @@
"postcss": "^8.1.0"
}
},
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/ignore": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
@@ -7665,6 +8504,15 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
+ "node_modules/ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/internal-slot": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
@@ -7764,11 +8612,23 @@
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"dev": true,
- "engines": {
- "node": ">= 0.4"
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-ci": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
+ "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
+ "dev": true,
+ "dependencies": {
+ "ci-info": "^3.2.0"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "bin": {
+ "is-ci": "bin.js"
}
},
"node_modules/is-core-module": {
@@ -7837,6 +8697,22 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "dev": true,
+ "dependencies": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
@@ -8007,6 +8883,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "dev": true
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-weakmap": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
@@ -8074,6 +8968,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
+ "dev": true
+ },
"node_modules/istanbul-lib-coverage": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
@@ -11216,6 +12116,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
+ "dev": true
+ },
"node_modules/jsdom": {
"version": "20.0.3",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
@@ -11279,6 +12185,12 @@
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true
},
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -11291,6 +12203,12 @@
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
"dev": true
},
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true
+ },
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
@@ -11303,6 +12221,42 @@
"node": ">=6"
}
},
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsonfile/node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/jsprim": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
+ "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.4.0",
+ "verror": "1.10.0"
+ }
+ },
"node_modules/jsx-ast-utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
@@ -11334,6 +12288,15 @@
"node": ">=6"
}
},
+ "node_modules/lazy-ass": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
+ "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
+ "dev": true,
+ "engines": {
+ "node": "> 0.8"
+ }
+ },
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -11362,6 +12325,33 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
+ "node_modules/listr2": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
+ "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==",
+ "dev": true,
+ "dependencies": {
+ "cli-truncate": "^2.1.0",
+ "colorette": "^2.0.16",
+ "log-update": "^4.0.0",
+ "p-map": "^4.0.0",
+ "rfdc": "^1.3.0",
+ "rxjs": "^7.5.1",
+ "through": "^2.3.8",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "enquirer": ">= 2.3.0 < 3"
+ },
+ "peerDependenciesMeta": {
+ "enquirer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/loader-runner": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
@@ -11409,35 +12399,230 @@
"node": ">=8"
}
},
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/lodash-webpack-plugin": {
- "version": "0.11.6",
- "resolved": "https://registry.npmjs.org/lodash-webpack-plugin/-/lodash-webpack-plugin-0.11.6.tgz",
- "integrity": "sha512-nsHN/+IxZK/C425vGC8pAxkKJ8KQH2+NJnhDul14zYNWr6HJcA95w+oRR7Cp0oZpOdMplDZXmjVROp8prPk7ig==",
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/lodash-webpack-plugin": {
+ "version": "0.11.6",
+ "resolved": "https://registry.npmjs.org/lodash-webpack-plugin/-/lodash-webpack-plugin-0.11.6.tgz",
+ "integrity": "sha512-nsHN/+IxZK/C425vGC8pAxkKJ8KQH2+NJnhDul14zYNWr6HJcA95w+oRR7Cp0oZpOdMplDZXmjVROp8prPk7ig==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.20"
+ },
+ "peerDependencies": {
+ "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.1.0"
+ }
+ },
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "dev": true
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/log-symbols/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-symbols/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+ "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^4.3.0",
+ "cli-cursor": "^3.1.0",
+ "slice-ansi": "^4.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/log-update/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/log-update/node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dev": true,
"dependencies": {
- "lodash": "^4.17.20"
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
},
- "peerDependencies": {
- "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.1.0"
+ "engines": {
+ "node": ">=8"
}
},
- "node_modules/lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
- "dev": true
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -11835,6 +13020,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/ospath": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz",
+ "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==",
+ "dev": true
+ },
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
@@ -11862,6 +13053,21 @@
"node": ">=8"
}
},
+ "node_modules/p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -11955,6 +13161,18 @@
"node": ">=8"
}
},
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "dev": true
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "dev": true
+ },
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -11973,6 +13191,15 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/pirates": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
@@ -12120,6 +13347,18 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
+ "node_modules/pretty-bytes": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/pretty-format": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
@@ -12201,12 +13440,28 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
+ "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==",
+ "dev": true
+ },
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
"dev": true
},
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -12216,6 +13471,15 @@
"node": ">=6"
}
},
+ "node_modules/qs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
+ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
@@ -12452,6 +13716,15 @@
"integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==",
"dev": true
},
+ "node_modules/request-progress": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz",
+ "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==",
+ "dev": true,
+ "dependencies": {
+ "throttleit": "^1.0.0"
+ }
+ },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -12520,6 +13793,19 @@
"node": ">=10"
}
},
+ "node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -12530,6 +13816,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/rfdc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+ "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==",
+ "dev": true
+ },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -12568,6 +13860,21 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/rxjs": {
+ "version": "7.5.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
+ "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/rxjs/node_modules/tslib": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
+ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
+ "dev": true
+ },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -12718,6 +14025,53 @@
"node": ">=8"
}
},
+ "node_modules/slice-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+ "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -12752,6 +14106,31 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
+ "node_modules/sshpk": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
+ "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
+ "dev": true,
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "bin": {
+ "sshpk-conv": "bin/sshpk-conv",
+ "sshpk-sign": "bin/sshpk-sign",
+ "sshpk-verify": "bin/sshpk-verify"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/stable": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
@@ -13193,6 +14572,30 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
+ "node_modules/throttleit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
+ "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==",
+ "dev": true
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "node_modules/tmp": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+ "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+ "dev": true,
+ "dependencies": {
+ "rimraf": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8.17.0"
+ }
+ },
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -13268,6 +14671,24 @@
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
}
},
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
+ "dev": true
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -13378,6 +14799,15 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/untildify": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
+ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/update-browserslist-db": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
@@ -13437,6 +14867,15 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true,
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/v8-to-istanbul": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
@@ -13451,6 +14890,20 @@
"node": ">=10.12.0"
}
},
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
@@ -13938,6 +15391,16 @@
"node": ">=12"
}
},
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dev": true,
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -15226,6 +16689,83 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@cypress/request": {
+ "version": "2.88.10",
+ "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz",
+ "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==",
+ "dev": true,
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "http-signature": "~1.3.6",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^8.3.2"
+ },
+ "dependencies": {
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ }
+ }
+ },
+ "@cypress/xvfb": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
+ "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==",
+ "dev": true,
+ "requires": {
+ "debug": "^3.1.0",
+ "lodash.once": "^4.1.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
"@discoveryjs/json-ext": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
@@ -16963,6 +18503,18 @@
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"dev": true
},
+ "@types/sinonjs__fake-timers": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz",
+ "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==",
+ "dev": true
+ },
+ "@types/sizzle": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
+ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
+ "dev": true
+ },
"@types/stack-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
@@ -16997,6 +18549,16 @@
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
},
+ "@types/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@typescript-eslint/eslint-plugin": {
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
@@ -17361,6 +18923,16 @@
"debug": "4"
}
},
+ "aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ }
+ },
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -17380,6 +18952,12 @@
"dev": true,
"requires": {}
},
+ "ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "dev": true
+ },
"ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
@@ -17422,6 +19000,12 @@
"picomatch": "^2.0.4"
}
},
+ "arch": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
+ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
+ "dev": true
+ },
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -17484,18 +19068,63 @@
"get-intrinsic": "^1.1.3"
}
},
+ "asn1": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
+ "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
+ "dev": true
+ },
+ "astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true
+ },
+ "async": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+ "dev": true
+ },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
},
+ "at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true
+ },
"available-typed-arrays": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
"dev": true
},
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
+ "dev": true
+ },
+ "aws4": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
+ "dev": true
+ },
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -17897,6 +19526,21 @@
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
+ "dev": true,
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -17909,6 +19553,18 @@
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true
},
+ "blob-util": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz",
+ "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==",
+ "dev": true
+ },
+ "bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -17955,12 +19611,34 @@
"node-int64": "^0.4.0"
}
},
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true
+ },
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
+ "cachedir": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz",
+ "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==",
+ "dev": true
+ },
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -17989,6 +19667,12 @@
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==",
"dev": true
},
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
+ "dev": true
+ },
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -18006,6 +19690,12 @@
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
"dev": true
},
+ "check-more-types": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
+ "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==",
+ "dev": true
+ },
"chokidar": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
@@ -18079,6 +19769,41 @@
}
}
},
+ "clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^3.1.0"
+ }
+ },
+ "cli-table3": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
+ "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
+ "dev": true,
+ "requires": {
+ "@colors/colors": "1.5.0",
+ "string-width": "^4.2.0"
+ }
+ },
+ "cli-truncate": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+ "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "dev": true,
+ "requires": {
+ "slice-ansi": "^3.0.0",
+ "string-width": "^4.2.0"
+ }
+ },
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -18166,6 +19891,12 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
+ "common-tags": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
+ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==",
+ "dev": true
+ },
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -18211,6 +19942,12 @@
"browserslist": "^4.21.4"
}
},
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
+ "dev": true
+ },
"cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -18352,6 +20089,174 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
+ "cypress": {
+ "version": "12.2.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.2.0.tgz",
+ "integrity": "sha512-kvl95ri95KK8mAy++tEU/wUgzAOMiIciZSL97LQvnOinb532m7dGvwN0mDSIGbOd71RREtmT9o4h088RjK5pKw==",
+ "dev": true,
+ "requires": {
+ "@cypress/request": "^2.88.10",
+ "@cypress/xvfb": "^1.2.4",
+ "@types/node": "^14.14.31",
+ "@types/sinonjs__fake-timers": "8.1.1",
+ "@types/sizzle": "^2.3.2",
+ "arch": "^2.2.0",
+ "blob-util": "^2.0.2",
+ "bluebird": "^3.7.2",
+ "buffer": "^5.6.0",
+ "cachedir": "^2.3.0",
+ "chalk": "^4.1.0",
+ "check-more-types": "^2.24.0",
+ "cli-cursor": "^3.1.0",
+ "cli-table3": "~0.6.1",
+ "commander": "^5.1.0",
+ "common-tags": "^1.8.0",
+ "dayjs": "^1.10.4",
+ "debug": "^4.3.2",
+ "enquirer": "^2.3.6",
+ "eventemitter2": "6.4.7",
+ "execa": "4.1.0",
+ "executable": "^4.1.1",
+ "extract-zip": "2.0.1",
+ "figures": "^3.2.0",
+ "fs-extra": "^9.1.0",
+ "getos": "^3.2.1",
+ "is-ci": "^3.0.0",
+ "is-installed-globally": "~0.4.0",
+ "lazy-ass": "^1.6.0",
+ "listr2": "^3.8.3",
+ "lodash": "^4.17.21",
+ "log-symbols": "^4.0.0",
+ "minimist": "^1.2.6",
+ "ospath": "^1.2.2",
+ "pretty-bytes": "^5.6.0",
+ "proxy-from-env": "1.0.0",
+ "request-progress": "^3.0.0",
+ "semver": "^7.3.2",
+ "supports-color": "^8.1.1",
+ "tmp": "~0.2.1",
+ "untildify": "^4.0.0",
+ "yauzl": "^2.10.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "commander": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+ "dev": true
+ },
+ "execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ }
+ },
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
"data-urls": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
@@ -18363,6 +20268,12 @@
"whatwg-url": "^11.0.0"
}
},
+ "dayjs": {
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz",
+ "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==",
+ "dev": true
+ },
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -18524,6 +20435,16 @@
"domhandler": "^4.2.0"
}
},
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
+ "dev": true,
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
"electron-to-chromium": {
"version": "1.4.284",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
@@ -18548,6 +20469,15 @@
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"dev": true
},
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
"enhanced-resolve": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
@@ -18558,6 +20488,15 @@
"tapable": "^2.2.0"
}
},
+ "enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^4.1.1"
+ }
+ },
"entities": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
@@ -18943,6 +20882,15 @@
"dev": true,
"requires": {}
},
+ "eslint-plugin-cypress": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz",
+ "integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==",
+ "dev": true,
+ "requires": {
+ "globals": "^11.12.0"
+ }
+ },
"eslint-plugin-react": {
"version": "7.31.11",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz",
@@ -19099,6 +21047,12 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "eventemitter2": {
+ "version": "6.4.7",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
+ "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
+ "dev": true
+ },
"events": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
@@ -19122,6 +21076,15 @@
"strip-final-newline": "^2.0.0"
}
},
+ "executable": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
+ "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
+ "dev": true,
+ "requires": {
+ "pify": "^2.2.0"
+ }
+ },
"exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -19149,6 +21112,41 @@
}
}
},
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "requires": {
+ "@types/yauzl": "^2.9.1",
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ }
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
+ "dev": true
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -19204,6 +21202,24 @@
"bser": "2.1.1"
}
},
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dev": true,
+ "requires": {
+ "pend": "~1.2.0"
+ }
+ },
+ "figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
"file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -19268,6 +21284,12 @@
"is-callable": "^1.1.3"
}
},
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
+ "dev": true
+ },
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@@ -19279,6 +21301,26 @@
"mime-types": "^2.1.12"
}
},
+ "fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "dependencies": {
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true
+ }
+ }
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -19354,6 +21396,24 @@
"get-intrinsic": "^1.1.1"
}
},
+ "getos": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
+ "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==",
+ "dev": true,
+ "requires": {
+ "async": "^3.2.0"
+ }
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
@@ -19383,6 +21443,15 @@
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"dev": true
},
+ "global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "dev": true,
+ "requires": {
+ "ini": "2.0.0"
+ }
+ },
"globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -19512,6 +21581,17 @@
"debug": "4"
}
},
+ "http-signature": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz",
+ "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^2.0.2",
+ "sshpk": "^1.14.1"
+ }
+ },
"https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -19544,6 +21624,12 @@
"dev": true,
"requires": {}
},
+ "ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true
+ },
"ignore": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
@@ -19606,6 +21692,12 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
+ "ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "dev": true
+ },
"internal-slot": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
@@ -19682,6 +21774,15 @@
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"dev": true
},
+ "is-ci": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
+ "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
+ "dev": true,
+ "requires": {
+ "ci-info": "^3.2.0"
+ }
+ },
"is-core-module": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
@@ -19727,6 +21828,16 @@
"is-extglob": "^2.1.1"
}
},
+ "is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "dev": true,
+ "requires": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ }
+ },
"is-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
@@ -19837,6 +21948,18 @@
"has-tostringtag": "^1.0.0"
}
},
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "dev": true
+ },
+ "is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true
+ },
"is-weakmap": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
@@ -19886,6 +22009,12 @@
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true
},
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
+ "dev": true
+ },
"istanbul-lib-coverage": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
@@ -22277,6 +24406,12 @@
"esprima": "^4.0.0"
}
},
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
+ "dev": true
+ },
"jsdom": {
"version": "20.0.3",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
@@ -22323,6 +24458,12 @@
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true
},
+ "json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true
+ },
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -22335,12 +24476,48 @@
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
"dev": true
},
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true
+ },
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"dev": true
},
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ },
+ "dependencies": {
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true
+ }
+ }
+ },
+ "jsprim": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
+ "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==",
+ "dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.4.0",
+ "verror": "1.10.0"
+ }
+ },
"jsx-ast-utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
@@ -22363,6 +24540,12 @@
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dev": true
},
+ "lazy-ass": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
+ "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
+ "dev": true
+ },
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -22385,6 +24568,22 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
+ "listr2": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
+ "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==",
+ "dev": true,
+ "requires": {
+ "cli-truncate": "^2.1.0",
+ "colorette": "^2.0.16",
+ "log-update": "^4.0.0",
+ "p-map": "^4.0.0",
+ "rfdc": "^1.3.0",
+ "rxjs": "^7.5.1",
+ "through": "^2.3.8",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
"loader-runner": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
@@ -22448,6 +24647,148 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "log-update": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+ "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^4.3.0",
+ "cli-cursor": "^3.1.0",
+ "slice-ansi": "^4.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ }
+ }
+ },
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -22746,6 +25087,12 @@
"word-wrap": "^1.2.3"
}
},
+ "ospath": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz",
+ "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==",
+ "dev": true
+ },
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
@@ -22764,6 +25111,15 @@
"p-limit": "^2.2.0"
}
},
+ "p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -22830,6 +25186,18 @@
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "dev": true
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "dev": true
+ },
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -22842,6 +25210,12 @@
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
},
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true
+ },
"pirates": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
@@ -22940,6 +25314,12 @@
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"dev": true
},
+ "pretty-bytes": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
+ "dev": true
+ },
"pretty-format": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
@@ -23005,18 +25385,40 @@
"react-is": "^16.13.1"
}
},
+ "proxy-from-env": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
+ "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==",
+ "dev": true
+ },
"psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
"dev": true
},
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
},
+ "qs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
+ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+ "dev": true
+ },
"querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
@@ -23195,6 +25597,15 @@
"integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==",
"dev": true
},
+ "request-progress": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz",
+ "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==",
+ "dev": true,
+ "requires": {
+ "throttleit": "^1.0.0"
+ }
+ },
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -23245,12 +25656,28 @@
"integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==",
"dev": true
},
+ "restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "requires": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
"reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true
},
+ "rfdc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+ "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==",
+ "dev": true
+ },
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -23269,6 +25696,23 @@
"queue-microtask": "^1.2.2"
}
},
+ "rxjs": {
+ "version": "7.5.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
+ "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^2.1.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
+ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
+ "dev": true
+ }
+ }
+ },
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -23388,6 +25832,43 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
+ "slice-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+ "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ }
+ }
+ },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -23416,6 +25897,23 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
+ "sshpk": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
+ "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
+ "dev": true,
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
"stable": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
@@ -23732,6 +26230,27 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
+ "throttleit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
+ "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "tmp": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+ "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+ "dev": true,
+ "requires": {
+ "rimraf": "^3.0.0"
+ }
+ },
"tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -23789,6 +26308,21 @@
"tslib": "^1.8.1"
}
},
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
+ "dev": true
+ },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -23862,6 +26396,12 @@
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"dev": true
},
+ "untildify": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
+ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
+ "dev": true
+ },
"update-browserslist-db": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
@@ -23903,6 +26443,12 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
+ "uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true
+ },
"v8-to-istanbul": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
@@ -23914,6 +26460,17 @@
"convert-source-map": "^1.6.0"
}
},
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
"w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
@@ -24255,6 +26812,16 @@
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true
},
+ "yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index 1d34e80a..56a1f184 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,9 @@
"build:css": "csso ./csm_web/frontend/static/frontend/css/style.css --output ./csm_web/frontend/static/frontend/css/style.min.css",
"build": "npm run build:js && npm run build:css",
"watch": "webpack --mode development --watch",
- "test": "jest"
+ "test": "jest",
+ "cypress:open": "cypress open",
+ "cypress:run": "cypress run --e2e --record=false --config video=false,screenshotOnRunFailure=false"
},
"heroku-run-build-script": true,
"repository": {
@@ -47,8 +49,10 @@
"babel-polyfill": "^6.26.0",
"css-loader": "^6.2.0",
"csso-cli": "^3.0.0",
+ "cypress": "^12.2.0",
"eslint": "^8.27.0",
"eslint-config-prettier": "^7.2.0",
+ "eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-react": "^7.31.10",
"eslint-plugin-react-hooks": "^4.6.0",
"jest": "^28.1.1",