Skip to content

Commit 88315cc

Browse files
committed
Merge branch 'master' of https://github.com/justin212407/musicblocks into play-only-mode
2 parents 18f96d5 + 5e12c44 commit 88315cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+11687
-7464
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Run Jest Tests on PR
2+
3+
on:
4+
pull_request_target:
5+
types:
6+
- opened
7+
- synchronize
8+
9+
jobs:
10+
test:
11+
name: Run Jest Tests
12+
runs-on: ubuntu-latest
13+
permissions:
14+
pull-requests: write
15+
contents: read
16+
issues: write
17+
18+
steps:
19+
- name: Checkout Repository
20+
uses: actions/checkout@v4
21+
with:
22+
ref: ${{ github.event.pull_request.head.sha }}
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: '20'
28+
29+
- name: Install Dependencies
30+
run: npm install
31+
32+
- name: Run Jest Tests
33+
id: jest
34+
run: |
35+
npm test -- --json --outputFile=jest-results.json || echo "TESTS_FAILED=true" >> $GITHUB_ENV
36+
37+
- name: Read Jest Results
38+
id: results
39+
run: |
40+
# Default TESTS_FAILED to false
41+
if [ -z "$TESTS_FAILED" ]; then
42+
TESTS_FAILED=false
43+
fi
44+
45+
# Set TESTS_PASSED properly
46+
if [ "$TESTS_FAILED" = "true" ]; then
47+
TESTS_PASSED=false
48+
echo "TESTS_PASSED=false" >> $GITHUB_ENV
49+
FAILED_TESTS=$(jq -r '[.testResults[] | select(.status == "failed") | .name] | map(split("/") | last) | join("\n")' jest-results.json)
50+
echo "FAILED_TESTS<<EOF" >> $GITHUB_ENV
51+
echo "$FAILED_TESTS" >> $GITHUB_ENV
52+
echo "EOF" >> $GITHUB_ENV
53+
else
54+
TESTS_PASSED=true
55+
echo "TESTS_PASSED=true" >> $GITHUB_ENV
56+
echo "FAILED_TESTS=None" >> $GITHUB_ENV
57+
fi
58+
59+
# Extract PR number
60+
PR_NUMBER=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
61+
62+
# Generate a temporary file for the comment
63+
COMMENT_FILE=$(mktemp)
64+
65+
# Save variables to GITHUB_OUTPUT
66+
echo "TESTS_PASSED=$TESTS_PASSED" >> $GITHUB_ENV
67+
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
68+
echo "COMMENT_FILE=$COMMENT_FILE" >> $GITHUB_OUTPUT
69+
70+
# Generate content for the comment file
71+
{
72+
if [ "$TESTS_PASSED" = "true" ]; then
73+
echo "✅ All Jest tests passed! This PR is ready to merge."
74+
else
75+
echo "❌ Some Jest tests failed. Please check the logs and fix the issues before merging."
76+
echo ""
77+
echo "**Failed Tests:**"
78+
echo ""
79+
echo '```'
80+
echo "$FAILED_TESTS"
81+
echo '```'
82+
fi
83+
} > "$COMMENT_FILE"
84+
85+
- name: PR comment
86+
uses: thollander/actions-comment-pull-request@v3
87+
with:
88+
file-path: ${{ steps.results.outputs.COMMENT_FILE }}
89+
pr-number: ${{ steps.results.outputs.PR_NUMBER }}
90+
github-token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/weblate-sync.yaml

Lines changed: 0 additions & 14 deletions
This file was deleted.

css/themes.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,17 @@
104104
color: white;
105105
}
106106

107+
.dark .dropdown-content li > a {
108+
background-color: #1c1c1c;
109+
color: #3fe0d1;
110+
}
111+
112+
.dark .dropdown-content li > a:hover {
113+
background-color: #333;
114+
}
107115

116+
.dark .dropdown-content {
117+
background-color: #1c1c1c;
118+
}
108119

109120
/* Your Custom Theme can go here if you don't want to modify the existing dark mode */

cypress.config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const { defineConfig } = require("cypress");
2+
3+
module.exports = defineConfig({
4+
e2e: {
5+
setupNodeEvents(on, config) {
6+
// implement node event listeners here
7+
},
8+
viewportWidth: 1400,
9+
viewportHeight: 1000,
10+
testIsolation: false
11+
},
12+
});

cypress/e2e/main.cy.js

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
Cypress.on("uncaught:exception", (err, runnable) => {
2+
return false;
3+
});
4+
5+
describe("MusicBlocks Application", () => {
6+
before(() => {
7+
cy.visit("http://localhost:3000");
8+
});
9+
10+
afterEach(() => {
11+
console.log("Next test running, no reload should happen");
12+
});
13+
14+
describe("Loading and Initial Render", () => {
15+
it("should display the loading animation and then the main content", () => {
16+
cy.get("#loading-image-container").should("be.visible");
17+
cy.contains("#loadingText", "Loading Complete!", { timeout: 20000 }).should("be.visible");
18+
cy.wait(10000);
19+
cy.get("#canvas", { timeout: 10000 }).should("be.visible");
20+
});
21+
22+
it("should display the Musicblocks guide page", () => {
23+
cy.get(".heading").contains("Welcome to Music Blocks");
24+
});
25+
});
26+
27+
describe("Audio Controls", () => {
28+
it("should have a functional play button", () => {
29+
cy.get("#play").should("be.visible").click();
30+
cy.window().then((win) => {
31+
const audioContext = win.Tone.context;
32+
cy.wrap(audioContext.state).should("eq", "running");
33+
});
34+
});
35+
36+
it("should have a functional stop button", () => {
37+
cy.get("#stop").should("be.visible").click();
38+
});
39+
});
40+
41+
describe("Toolbar and Navigation", () => {
42+
it("should open the language selection dropdown", () => {
43+
cy.get("#aux-toolbar").invoke("show");
44+
cy.get("#languageSelectIcon").click({ force: true });
45+
cy.get("#languagedropdown").should("be.visible");
46+
});
47+
48+
it("should toggle full-screen mode", () => {
49+
cy.get("#FullScreen").click();
50+
cy.document().its("fullscreenElement").should("exist");
51+
cy.get("#FullScreen").click();
52+
cy.document().its("fullscreenElement").should("not.exist");
53+
});
54+
55+
it("should toggle the toolbar menu", () => {
56+
cy.get("#toggleAuxBtn").click();
57+
cy.get("#aux-toolbar").should("be.visible");
58+
cy.get("#toggleAuxBtn").click();
59+
cy.get("#aux-toolbar").should("not.be.visible");
60+
});
61+
});
62+
63+
describe("File Operations", () => {
64+
it("should open the file load modal", () => {
65+
cy.get("#load").click();
66+
cy.get("#myOpenFile").should("exist");
67+
});
68+
69+
it("should open the save dropdown", () => {
70+
cy.get("#saveButton").click();
71+
cy.get("#saveddropdownbeg").should("be.visible");
72+
});
73+
74+
it("should display file save options", () => {
75+
cy.get("#saveButton").click();
76+
cy.get("#saveddropdownbeg").should("be.visible");
77+
cy.get("#save-html-beg").should("exist");
78+
cy.get("#save-png-beg").should("exist");
79+
});
80+
81+
it('should click the New File button and verify "New Project" appears', () => {
82+
cy.get('#newFile > .material-icons')
83+
.should('exist')
84+
.and('be.visible');
85+
cy.get('#newFile > .material-icons').click();
86+
cy.wait(500);
87+
cy.contains('New project').should('be.visible');
88+
});
89+
});
90+
91+
describe("UI Elements", () => {
92+
it('should verify that bottom bar elements exist and are visible', () => {
93+
const bottomBarElements = [
94+
'#Home\\ \\[HOME\\] > img',
95+
'#Show\\/hide\\ blocks > img',
96+
'#Expand\\/collapse\\ blocks > img',
97+
'#Decrease\\ block\\ size > img',
98+
'#Increase\\ block\\ size > img'
99+
];
100+
101+
bottomBarElements.forEach(selector => {
102+
cy.get(selector).should('exist').and('be.visible');
103+
});
104+
});
105+
106+
it('should verify sidebar elements exist, are visible, and clickable', () => {
107+
const sidebarElements = [
108+
'thead > tr > :nth-child(1) > img',
109+
'tr > :nth-child(2) > img',
110+
'tr > :nth-child(3) > img'
111+
];
112+
113+
sidebarElements.forEach(selector => {
114+
cy.get(selector)
115+
.should('exist')
116+
.and('be.visible')
117+
.click();
118+
});
119+
});
120+
121+
it('should verify that Grid, Clear, and Collapse elements exist and are visible', () => {
122+
const elements = [
123+
'#Grid > img',
124+
'#Clear',
125+
'#Collapse > img'
126+
];
127+
elements.forEach(selector => {
128+
cy.get(selector).should('exist').and('be.visible');
129+
});
130+
});
131+
132+
it('should verify that all nth-child elements from 1 to 6 exist', () => {
133+
for (let i = 1; i <= 6; i++) {
134+
cy.get(`[width="126"] > tbody > :nth-child(${i})`)
135+
.should('exist')
136+
.and('be.visible');
137+
}
138+
});
139+
});
140+
141+
describe("Planet Page Interaction", () => {
142+
it('should load the Planet page and return to the main page when clicking the close button', () => {
143+
cy.get('#planetIcon > .material-icons')
144+
.should('exist')
145+
.and('be.visible')
146+
.click();
147+
cy.get('#planet-iframe')
148+
.should('be.visible');
149+
});
150+
});
151+
152+
});

cypress/fixtures/example.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "Using fixtures to represent data",
3+
"email": "[email protected]",
4+
"body": "Fixtures are a great way to mock data for responses to routes"
5+
}

cypress/support/commands.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// ***********************************************
2+
// This example commands.js shows you how to
3+
// create various custom commands and overwrite
4+
// existing commands.
5+
//
6+
// For more comprehensive examples of custom
7+
// commands please read more here:
8+
// https://on.cypress.io/custom-commands
9+
// ***********************************************
10+
//
11+
//
12+
// -- This is a parent command --
13+
// Cypress.Commands.add('login', (email, password) => { ... })
14+
//
15+
//
16+
// -- This is a child command --
17+
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
18+
//
19+
//
20+
// -- This is a dual command --
21+
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
22+
//
23+
//
24+
// -- This will overwrite an existing command --
25+
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

cypress/support/e2e.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// ***********************************************************
2+
// This example support/e2e.js is processed and
3+
// loaded automatically before your test files.
4+
//
5+
// This is a great place to put global configuration and
6+
// behavior that modifies Cypress.
7+
//
8+
// You can change the location of this file or turn off
9+
// automatically serving support files with the
10+
// 'supportFile' configuration option.
11+
//
12+
// You can read more here:
13+
// https://on.cypress.io/configuration
14+
// ***********************************************************
15+
16+
// Import commands.js using ES2015 syntax:
17+
import './commands'

dist/css/keyboard.css

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@
88
cursor: pointer;
99
position: relative;
1010
}
11+
12+
#countdownContainer {
13+
position: absolute;
14+
top: 0;
15+
left: 0;
16+
width: 100%;
17+
height: 100%;
18+
z-index: 200;
19+
background: rgba(53, 53, 53, 0.492);
20+
pointer-events: all;
21+
}
22+
23+
#countdownDisplay {
24+
position: absolute;
25+
top: 50%;
26+
left: 50%;
27+
transform: translate(-50%, -50%);
28+
background: black;
29+
color: white;
30+
padding: 20px;
31+
border-radius: 10px;
32+
text-align: center;
33+
}
34+
1135
table {
1236
table-layout: fixed;
1337
}

documentation/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ The **Main** toolbar is located across the top of the screen. It contains severa
102102

103103
- **Play Button**: Starts playing the project.
104104
- **Stop Button**: Stops the current project playback.
105+
- **Fullscreen Button**: Toggles fullscreen mode on or off.
105106
- **New Project Button**: Creates a new project from scratch.
106107
- **Load Project from File Button**: Opens an existing project file.
107108
- **Save Project Button**: Saves the current project.
@@ -117,6 +118,7 @@ The **Secondary** toolbar appears when you click the **hamburger button** (three
117118

118119
- **Run Slowly**: Executes the program slowly to allow you to follow the process step by step.
119120
- **Run Step by Step**: Runs the program one step at a time, ideal for debugging and analysis.
121+
- **Change theme**: Switch between light and dark mode for a customized workspace.
120122
- **Merge with Current Project**: Combines the current project with another, promoting collaboration and reusability.
121123
- **Turtle Wrap**: Enables wrapping of the turtle's position to seamlessly continue from the opposite edge of the canvas.
122124
- **Set Pitch Preview**: Lets users preview pitches while composing, providing instant feedback.
@@ -128,7 +130,7 @@ The **Secondary** toolbar appears when you click the **hamburger button** (three
128130
3. *Delete Plugin*: Allows the removal of plugins that are no longer needed.<br>
129131
4. *Horizontal Scrolling*: Enables horizontal navigation for easier handling of large projects.<br>
130132
5. *JavaScript Editor*: Includes an editor for writing and embedding custom JavaScript code.<br>
131-
6.*Record*: Adds a "Record" button to the main palette, enabling users to record their compositions directly.
133+
6. *Record*: Adds a "Record" button to the main palette, enabling users to record their compositions directly.
132134

133135
- **Select Language**: Offers a multilingual interface, allowing users to change the language as per their preference.
134136

0 commit comments

Comments
 (0)