songs2slides

A tool that automatically finds song lyrics and creates lyric slideshows
git clone https://git.ashermorgan.net/songs2slides/
Log | Files | Refs | README

commit 68422e4751bd55940f68442c219a8821e1a1c1ef
parent 25ec8d939ba49304aad35a9e5e65be81d10e912a
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Sat, 20 Apr 2024 13:19:01 -0700

Add screenshots

Diffstat:
MREADME.md | 11+++++++++++
Mmock_api.py | 6+++---
Ascreenshots/slides.png | 0
Ascreenshots/step-1.png | 0
Ascreenshots/step-2.png | 0
Ascreenshots/step-3.png | 0
Atests/conftest.py | 44++++++++++++++++++++++++++++++++++++++++++++
Atests/generate_screenshots.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/test_e2e.py | 56++++++--------------------------------------------------
9 files changed, 119 insertions(+), 53 deletions(-)

diff --git a/README.md b/README.md @@ -20,3 +20,14 @@ Run Songs2Slides on [localhost:5000](http://localhost:5000) ``` flask --app songs2slides run ``` + +## Screenshots +Screenshots of Songs2Slides with `mock_api.py` as the API: + +![Step 1: Select Songs](screenshots/step-1.png) + +![Step 2: Review lyrics](screenshots/step-2.png) + +![Step 3: Create slideshow](screenshots/step-3.png) + +![Completed slideshow](screenshots/slides.png) diff --git a/mock_api.py b/mock_api.py @@ -8,17 +8,17 @@ SONGS = { 'song 1': { 'title': 'Song 1', 'artist': 'Artist A', - 'lyrics': 'Lyrics to song 1\nby artist A', + 'lyrics': 'These are the lyrics\nto song 1\nby artist A', }, 'song 2': { 'title': 'Song 2', 'artist': 'Artist A', - 'lyrics': 'Lyrics to song 2\nby artist A', + 'lyrics': 'These are the lyrics\nto song 2\nby artist A', }, 'song 3': { 'title': 'Song 3', 'artist': 'Artist B', - 'lyrics': 'Lyrics to song 3\nby artist B', + 'lyrics': 'These are the lyrics\nto song 3\nby artist B', }, } diff --git a/screenshots/slides.png b/screenshots/slides.png Binary files differ. diff --git a/screenshots/step-1.png b/screenshots/step-1.png Binary files differ. diff --git a/screenshots/step-2.png b/screenshots/step-2.png Binary files differ. diff --git a/screenshots/step-3.png b/screenshots/step-3.png Binary files differ. diff --git a/tests/conftest.py b/tests/conftest.py @@ -0,0 +1,44 @@ +import os +import pytest +from xprocess import ProcessStarter + +@pytest.fixture(scope='session') +def api(xprocess): + port = '5003' + + class Starter(ProcessStarter): + pattern = '.*Running.*' + timeout = 10 + args = ['python', '-m', 'flask', '--app', '../../../../mock_api.py', + 'run', '--port', port] + + # Start API + xprocess.ensure('api', Starter) + + yield f'http://localhost:{port}' + + # Stop API + xprocess.getinfo('api').terminate() + +@pytest.fixture(scope='session') +def server(xprocess, api): + port = '5002' + + class Starter(ProcessStarter): + pattern = '.*Running.*' + timeout = 10 + args = ['python', '-m', 'flask', '--app', '../../../../songs2slides', + 'run', '--port', port] + env = os.environ | { 'API_URL': api + '/{title}/{artist}/' } + + # Start server + xprocess.ensure('server', Starter) + + yield f'http://localhost:{port}' + + # Stop server + xprocess.getinfo('server').terminate() + +@pytest.fixture(scope='session') +def base_url(server): + return server diff --git a/tests/generate_screenshots.py b/tests/generate_screenshots.py @@ -0,0 +1,55 @@ +# Run with: pytest tests/generate_screenshots.py +# (not run by default due to lack of test_* filename prefix) + +from playwright.sync_api import Page + +def test_generate_screenshots(page: Page): + # Set viewport size + page.set_viewport_size({'width': 800, 'height': 380}) + + # Start on homepage + page.goto('/') + + # Click 'Create a Slideshow' + page.get_by_role('link', name='Create a Slideshow').click() + + # Fill in song information + page.get_by_placeholder('Song title').last.fill('Song 1') + page.get_by_placeholder('Song artist').last.fill('Artist A') + page.get_by_role('button', name='Add Song').click() + page.get_by_placeholder('Song title').last.fill('Song 4') + page.get_by_placeholder('Song artist').last.fill('Artist C') + page.get_by_placeholder('Song artist').last.blur() + + # Take step 1 screenshot + page.screenshot(path='screenshots/step-1.png', full_page=True) + + # Click Next + page.get_by_role('button', name='Next').click() + + # Uncollapse Song 1 + page.get_by_text('Song 1 (Artist A)').click() + + # Shrink textareas (for a more compact screenshot) + page.add_style_tag(content='textarea { height: 65px } .missing textarea { height: 40px }') + + # Take step 2 screenshot + page.screenshot(path='screenshots/step-2.png', full_page=True) + + # Click Next + page.get_by_role('button', name='Next').click() + + # Fill in slideshow settings + page.get_by_role('checkbox', name='Include a title slide before each song').uncheck() + + # Take step 3 screenshot + page.screenshot(path='screenshots/step-3.png', full_page=True) + + # Click create + page.get_by_role('button', name='Create').click() + + # Hide header (for better screenshot) + page.add_style_tag(content='header { display: none }') + + # Take slides screenshot + page.screenshot(path='screenshots/slides.png', full_page=True) diff --git a/tests/test_e2e.py b/tests/test_e2e.py @@ -1,48 +1,4 @@ -import os -import pytest from playwright.sync_api import Page, expect -from xprocess import ProcessStarter - -@pytest.fixture(autouse=True, scope='session') -def api(xprocess): - port = '5003' - - class Starter(ProcessStarter): - pattern = '.*Running.*' - timeout = 10 - args = ['python', '-m', 'flask', '--app', '../../../../mock_api.py', - 'run', '--port', port] - - # Start API - xprocess.ensure('api', Starter) - - yield f'http://localhost:{port}' - - # Stop API - xprocess.getinfo('api').terminate() - -@pytest.fixture(autouse=True, scope='session') -def server(xprocess, api): - port = '5002' - - class Starter(ProcessStarter): - pattern = '.*Running.*' - timeout = 10 - args = ['python', '-m', 'flask', '--app', '../../../../songs2slides', - 'run', '--port', port] - env = os.environ | { 'API_URL': api + '/{title}/{artist}/' } - - # Start server - xprocess.ensure('server', Starter) - - yield f'http://localhost:{port}' - - # Stop server - xprocess.getinfo('server').terminate() - -@pytest.fixture(autouse=True, scope='session') -def base_url(server): - return server def test_basic(page: Page): # Start on homepage @@ -80,7 +36,7 @@ def test_basic(page: Page): # Assert song lyrics are loaded (Song 1 lyrics uncollapsed) expect(page.get_by_role('textbox')).to_have_count(2) - expect(page.get_by_role('textbox').first).to_have_value('Lyrics to song 1\nby artist A') + expect(page.get_by_role('textbox').first).to_have_value('These are the lyrics\nto song 1\nby artist A') expect(page.get_by_role('textbox').last).to_have_value('') # Fill in missing lyrics @@ -98,7 +54,7 @@ def test_basic(page: Page): expect(page).to_have_url('http://localhost:5002/slides/') # Assert slide content is correct - expect(page.locator('css=section.present')).to_have_text('LYRICS TO SONG 1\nBY ARTIST A') + expect(page.locator('css=section.present')).to_have_text('THESE ARE THE LYRICS\nTO SONG 1\nBY ARTIST A') page.keyboard.press('ArrowRight') expect(page.locator('css=section.present')).to_have_text('') page.keyboard.press('ArrowRight') @@ -269,7 +225,7 @@ def test_back(page: Page): # Assert songs lyrics are loaded expect(page.get_by_role('textbox')).to_have_count(2) - expect(page.get_by_role('textbox').first).to_have_value('Lyrics to song 1\nby artist A') + expect(page.get_by_role('textbox').first).to_have_value('These are the lyrics\nto song 1\nby artist A') expect(page.get_by_role('textbox').last).to_have_value('') # Fill in bad missing lyrics @@ -288,7 +244,7 @@ def test_back(page: Page): # Assert bad song lyrics are still loaded expect(page.get_by_role('textbox')).to_have_count(2) - expect(page.get_by_role('textbox').first).to_have_value('Lyrics to song 1\nby artist A') + expect(page.get_by_role('textbox').first).to_have_value('These are the lyrics\nto song 1\nby artist A') expect(page.get_by_role('textbox').last).to_have_value('custom song 5 lyrics (bad)') # Fill in correct missing lyrics @@ -308,7 +264,7 @@ def test_back(page: Page): # Assert slide content is correct expect(page.locator('css=section.present')).to_have_text('SONG 1') page.keyboard.press('ArrowRight') - expect(page.locator('css=section.present')).to_have_text('LYRICS TO SONG 1\nBY ARTIST A') + expect(page.locator('css=section.present')).to_have_text('THESE ARE THE LYRICS\nTO SONG 1\nBY ARTIST A') page.keyboard.press('ArrowRight') expect(page.locator('css=section.present')).to_have_text('SONG 5') page.keyboard.press('ArrowRight') @@ -332,7 +288,7 @@ def test_back(page: Page): expect(page).to_have_url('http://localhost:5002/slides/') # Assert slide content is correct - expect(page.locator('css=section.present')).to_have_text('LYRICS TO SONG 1\nBY ARTIST A') + expect(page.locator('css=section.present')).to_have_text('THESE ARE THE LYRICS\nTO SONG 1\nBY ARTIST A') page.keyboard.press('ArrowRight') expect(page.locator('css=section.present')).to_have_text('CUSTOM SONG 5 LYRICS') page.keyboard.press('ArrowRight')