Add an account block showing who is signed in

[us_account], or the Account block: the signed-in visitor's name, their
email, a Sign out link, and — only when the account books for someone
besides itself — the students it books for. A parent's first question on
seeing "signed in as Grace" is whether this is the account their children's
lessons are on.

Two decisions worth naming.

Signed out with no login page chosen, the block renders nothing. Its whole
subject is the person signed in, which a stranger is not, and a bare "you
are not signed in" in a site header is noise with no way to act on it. With
a login page chosen it offers a Sign in link instead. The editor preview is
populated regardless, so the block is never an invisible box to the person
placing it.

Signing out returns to the chosen login page, or to the current page when
there is none. A block meant for a header should not also navigate someone
somewhere when they use it; the login page wins when configured, because the
page they were on may well be members-only.

The name comes from UserName::format(), so the block never exposes a
username the way display_name can.

Also brings docs/features/editor-blocks.md back in step: it still described
"four shortcodes" and had never listed the family block.

Closes #142

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-07-29 22:39:20 -03:00
co-authored by Claude Opus 5
parent d554e35d80
commit 15d55d70d1
13 changed files with 430 additions and 7 deletions
+3
View File
@@ -13,6 +13,9 @@ each change under the current top section as you work.
## [1.3.1]
### Added
- An **Account** block (`[us_account]`) showing who is signed in — their name, their email, the students they book for if that is anyone besides themselves — and a **Sign out** link. Signing out returns to the login page chosen in the block, or to the page the visitor was already on when none is set, so putting it in a site header does not also move people somewhere. To a signed-out visitor it shows a **Sign in** link when a login page is chosen, and nothing at all when one is not: a panel about who is signed in has nothing to tell a stranger, and a notice they cannot act on is just clutter in a header.
### Security
- Signup now checks the password properly. The form scores it as you type with the same zxcvbn meter wp-admin uses and will not submit a weak one, and the server refuses — regardless of what the browser allowed — anything shorter than 8 characters, one of the well-known leaked passwords, one built from barely any distinct characters, or one containing your own name or email address. Composition rules ("must contain a symbol") are deliberately not imposed: they mostly produce predictable substitutions. Email addresses are validated on the server on every signup path, with a clear message when one is already registered.
+24
View File
@@ -549,6 +549,30 @@
color: #1a7d2e;
}
/*
* The account panel: who is signed in, and the way out. Sized to sit in a
* header or sidebar, so the rules stay minimal and inherit the theme's type —
* a block that lands in a site header should look like it belongs there.
*/
.us-account p {
margin: 0 0 4px;
}
.us-account-name {
font-weight: 600;
}
.us-account-email,
.us-account-students {
display: block;
font-size: 0.9em;
opacity: 0.75;
}
.us-account-actions {
margin-top: 8px;
}
/* Shown only in block-editor previews (see BlockPreview). */
.us-editor-note {
font-size: 0.85em;
+22
View File
@@ -307,6 +307,28 @@
})
),
},
{
name: 'us-scheduler/account',
title: __('Account', 'unsupervised-schedular'),
description: __('Shows who is signed in, who they book for, and a sign out link. Renders nothing for signed-out visitors unless a login page is chosen.', 'unsupervised-schedular'),
icon: 'admin-users',
keywords: ['account', 'sign out', 'log out', 'signed in', 'profile'],
shortcode: 'us_account',
attributes: {
loginPageId: { type: 'number', default: 0 },
},
inspector: (attributes, setAttributes) => el(
PanelBody,
{ title: __('Signing in and out', 'unsupervised-schedular') },
el(PageSelect, {
label: __('Login page', 'unsupervised-schedular'),
help: __('Where signing out returns to, and where signed-out visitors are offered a link to sign in. Without one, signing out returns to the current page and signed-out visitors see nothing.', 'unsupervised-schedular'),
defaultLabel: __('Stay on the current page', 'unsupervised-schedular'),
value: attributes.loginPageId,
onChange: (loginPageId) => setAttributes({ loginPageId }),
})
),
},
];
blocks.forEach((def) => {
+30 -4
View File
@@ -1,8 +1,8 @@
# Editor Blocks
Gutenberg dynamic-block wrappers for the plugin's four front-end shortcodes,
so the pages can be previewed and styled inside the block editor instead of
appearing as grey shortcode text.
Gutenberg dynamic-block wrappers for the plugin's front-end shortcodes, so the
pages can be previewed and styled inside the block editor instead of appearing
as grey shortcode text.
## Blocks
@@ -12,6 +12,8 @@ appearing as grey shortcode text.
| `us-scheduler/student-login` | `[us_student_login]` | `Auth\LoginPage::render()` |
| `us-scheduler/student-register` | `[us_student_register]` | `Auth\RegistrationPage::render()` |
| `us-scheduler/group-classes` | `[us_group_classes]` | `GroupClass\GroupClassPage::render()` |
| `us-scheduler/family` | `[us_family]` | `Guardian\FamilyPage::render()` |
| `us-scheduler/account` | `[us_account]` | `Auth\AccountPage::render()` |
The shortcodes remain registered for back-compat; blocks and shortcodes share
the same page objects (constructed once in `Plugin::boot()`), so front-end
@@ -21,7 +23,7 @@ transform.
## Block options
Four blocks have sidebar (inspector) options:
Most blocks have sidebar (inspector) options:
| Block | Attribute | Default | Effect |
|---|---|---|---|
@@ -34,6 +36,8 @@ Four blocks have sidebar (inspector) options:
| `us-scheduler/student-login` | `autoRedirect` (boolean) | `false` | Send logged-in visitors straight to the booking page instead of showing the link. Does nothing until a booking page is chosen. |
| `us-scheduler/student-register` | `loginPageId` (number) | `0` | Page students continue to once registration finishes — the "Sign in to your account" link after they confirm their email, and the "Continue to your account" link an invited student gets on the spot. `0` = the WordPress login screen for the confirmation link, and no link at all for the (already signed-in) invited student. Shortcode equivalent: `[us_student_register login_page_id="…"]`. |
| `us-scheduler/student-register` | `autoRedirect` (boolean) | `false` | Send students straight to that page instead of showing the link. Does nothing until a page is chosen — there is no login-screen fallback here. |
| `us-scheduler/family` | `loginPageId` (number) | `0` | Where visitors who are not signed in are sent to log in. Shortcode equivalent: `[us_family login_page_id="…"]`. |
| `us-scheduler/account` | `loginPageId` (number) | `0` | Where signing out returns to, and where a signed-out visitor is offered a **Sign in** link. `0` = signing out returns to the current page, and a signed-out visitor sees **nothing at all** — see below. Shortcode equivalent: `[us_account login_page_id="…"]`. |
| `us-scheduler/group-classes` | `offeringId` (number) | `0` | Restrict the page to a single group class, for embedding on a page dedicated to that class. The class description is then omitted — only the schedule, instructor, price and enrolment controls are shown, so the surrounding page's own copy is not repeated. `0` = browse all classes, descriptions included. Shortcode equivalent: `[us_group_classes offering="…"]`. |
The page selects list all published pages; if a chosen page is later deleted,
@@ -105,6 +109,10 @@ placeholder content:
- **Login** — the real `templates/frontend/login-page.php` template (it has
no request-state dependencies).
- **Registration** — a disabled sample of the `.us-register-form` fields.
- **Account** — a populated sample panel. Deliberately populated whatever the
editor user's own state: on the published page a signed-out visitor may see
nothing at all, and an empty box tells the person placing the block nothing
about where it will sit.
Each preview starts with a `.us-editor-note` paragraph explaining what the
published page shows instead. The note class only appears in editor previews.
@@ -118,5 +126,23 @@ published page shows instead. The note class only appears in editor previews.
and fallbacks.
- `tests/Unit/Auth/LoginPageTest.php` — logged-in booking-link targets and
fallbacks.
- `tests/Unit/Auth/AccountPageTest.php` — what each visitor sees, the
sign-out redirect target, and the signed-out empty render.
- `tests/Unit/BlockPreviewTest.php` — preview markup mirrors the live CSS
classes/ids and includes the editor note.
## The account block's signed-out behaviour
`us-scheduler/account` is the one block that can render **nothing**. It is meant
for a header, sidebar or account page, and its whole subject is the person
signed in — which a stranger is not. A bare "you are not signed in" in a site
header is noise that cannot be acted on, so:
- **No login page chosen** → empty string for signed-out visitors.
- **Login page chosen** → a single **Sign in** link.
Signed in, it shows the display name (`Auth\UserName::format()`, so a username
is never exposed), the account email, a **Sign out** link, and — only on an
account that books for someone other than itself — the students it books for.
Signing out returns to the chosen login page, or to the current page when there
is none, so a header sign-out does not also navigate the visitor somewhere.
+91
View File
@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace Unsupervised\Schedular\Auth;
use Unsupervised\Schedular\Guardian\GuardianService;
use Unsupervised\Schedular\Val;
/**
* Who is signed in, and the way out.
*
* Meant for a header, sidebar or account page — somewhere it sits alongside
* other content rather than being the whole of it. That shapes the two
* decisions below.
*/
class AccountPage {
public function __construct( private GuardianService $guardians ) {}
/**
* Renders the account shortcode/block output.
*
* Signed out, this renders a sign-in link when a login page is configured and
* **nothing at all** when one is not. A block whose whole job is "you are
* signed in as X" has nothing to say to a stranger, and a bare "you are not
* signed in" in a site header is noise with no way to act on it. The editor
* preview shows the populated state regardless, so the block is never
* invisible to the person placing it.
*
* @param array<int|string, mixed> $atts Block attributes (`loginPageId`) or
* shortcode attributes (`login_page_id`).
*/
public function render( array $atts ): string {
$loginPageId = Val::int( $atts['loginPageId'] ?? $atts['login_page_id'] ?? 0 );
$loginUrl = $this->pageUrl( $loginPageId );
wp_enqueue_style( 'us-scheduler' );
if ( ! is_user_logged_in() ) {
if ( null === $loginUrl ) {
return '';
}
return sprintf(
'<div class="us-account us-account-out"><a class="us-account-signin" href="%s">%s</a></div>',
esc_url( $loginUrl ),
esc_html__( 'Sign in', 'unsupervised-schedular' )
);
}
// Always a WP_User here — is_user_logged_in() above rules out the
// id-0 placeholder wp_get_current_user() returns for a visitor.
$user = wp_get_current_user();
$name = UserName::format( $user, get_current_user_id() );
$email = $user->user_email;
// Whose lessons this account books, when that is more than just their own.
// A parent's first question on seeing "signed in as Grace" is whether this
// is the account their children's lessons are on.
$students = [];
foreach ( $this->guardians->bookableStudents( get_current_user_id() ) as $student ) {
if ( ! $student['is_self'] ) {
$students[] = $student['name'];
}
}
// Back to where they were, so signing out of a header link does not also
// navigate them somewhere. The login page is the better landing spot when
// one is configured, since the current page may be members-only.
$logoutUrl = wp_logout_url( $loginUrl ?? (string) get_permalink() );
ob_start();
include USC_PLUGIN_DIR . 'templates/frontend/account-page.php';
return (string) ob_get_clean();
}
/**
* Permalink of a configured page, or null when none is chosen or the chosen
* page has since been deleted.
*/
private function pageUrl( int $pageId ): ?string {
if ( $pageId <= 0 ) {
return null;
}
$url = get_permalink( $pageId );
return is_string( $url ) ? $url : null;
}
}
+26
View File
@@ -210,6 +210,32 @@ class BlockPreview {
);
}
/**
* Sample account panel. Shown populated whatever the editor's own login
* state, since on the published page a signed-out visitor may see nothing at
* all and an empty box tells the person placing the block nothing.
*/
public static function account(): string {
return sprintf(
'<div class="us-account">%s'
. '<p class="us-account-who"><span class="us-account-name">%s</span>'
. '<span class="us-account-email">%s</span></p>'
. '<p class="us-account-students">%s</p>'
. '<p class="us-account-actions"><a class="us-account-signout" href="#">%s</a></p></div>',
self::note( __( 'Editor preview — each visitor sees their own account here.', 'unsupervised-schedular' ) ),
esc_html__( 'Grace Hopper', 'unsupervised-schedular' ),
esc_html__( '[email protected]', 'unsupervised-schedular' ),
esc_html(
sprintf(
/* translators: %s: comma-separated list of the students this account books for. */
__( 'Booking for %s', 'unsupervised-schedular' ),
__( 'Ada, Alan', 'unsupervised-schedular' )
)
),
esc_html__( 'Sign out', 'unsupervised-schedular' )
);
}
private static function note( string $text ): string {
return '<p class="us-editor-note">' . esc_html( $text ) . '</p>';
}
+20
View File
@@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Unsupervised\Schedular;
use Unsupervised\Schedular\Auth\AccountPage;
use Unsupervised\Schedular\Auth\LoginPage;
use Unsupervised\Schedular\Auth\RegistrationPage;
use Unsupervised\Schedular\Booking\BookingPage;
@@ -30,6 +31,7 @@ class BlockRegistrar {
private RegistrationPage $registrationPage,
private GroupClassPage $groupClassPage,
private FamilyPage $familyPage,
private AccountPage $accountPage,
) {}
public function register(): void {
@@ -148,6 +150,15 @@ class BlockRegistrar {
],
],
],
'us-scheduler/account' => [
'render' => [ $this, 'renderAccount' ],
'attributes' => [
'loginPageId' => [
'type' => 'number',
'default' => 0,
],
],
],
];
}
@@ -195,6 +206,15 @@ class BlockRegistrar {
return BlockPreview::groupClasses( Val::int( $attributes['offeringId'] ?? 0 ) > 0 );
}
/**
* Renders the account (who is signed in) block.
*
* @param array<string, mixed> $attributes Block attributes.
*/
public function renderAccount( array $attributes = [] ): string {
return $this->isEditorPreview() ? BlockPreview::account() : $this->accountPage->render( $attributes );
}
/**
* Renders the family (manage-children) block.
*
+4 -2
View File
@@ -5,6 +5,7 @@ namespace Unsupervised\Schedular;
use Unsupervised\Schedular\Auth\EmailConfirmationHandler;
use Unsupervised\Schedular\Auth\InviteRepository;
use Unsupervised\Schedular\Auth\AccountPage;
use Unsupervised\Schedular\Auth\LoginPage;
use Unsupervised\Schedular\Auth\RegistrationLoginGate;
use Unsupervised\Schedular\Auth\RegistrationMailer;
@@ -99,6 +100,7 @@ class Plugin {
$registrationPage = new RegistrationPage( $invites, $policies, $policyVersions, $acceptances, $settings, $registrationMailer, $questions, $answers, $groupAccess, $guardians );
$groupClassPage = new GroupClassPage( $guardians );
$familyPage = new FamilyPage( $guardians, $questions, $answers );
$accountPage = new AccountPage( $guardians );
( new ScheduledBillingRunner( $paymentService, $bookings, $enrollments, $offerings, new PaymentDueMailer(), $guardians ) )->register();
@@ -110,7 +112,7 @@ class Plugin {
( new EmailConfirmationHandler( $settings, $registrationMailer ) )->register();
( new AdminMenu( $availability, $bookings, $offerings, $questions, $answers, $policies, $policyVersions, $policyService, $acceptances, $invites, $enrollments, $groupAccess, $settings, $paymentRepo, $paymentService, $resolver, $registrationMailer, $creditRepo, $guardians ) )->register();
( new RestRegistrar( $availability, $bookings, $offerings, $questions, $policies, $policyVersions, $policyService, $registrationGate, $enrollments, $groupAccess, $paymentService, $guardians ) )->register();
( new ShortcodeRegistrar( $bookingPage, $loginPage, $registrationPage, $groupClassPage, $familyPage ) )->register();
( new BlockRegistrar( $bookingPage, $loginPage, $registrationPage, $groupClassPage, $familyPage ) )->register();
( new ShortcodeRegistrar( $bookingPage, $loginPage, $registrationPage, $groupClassPage, $familyPage, $accountPage ) )->register();
( new BlockRegistrar( $bookingPage, $loginPage, $registrationPage, $groupClassPage, $familyPage, $accountPage ) )->register();
}
}
+3
View File
@@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Unsupervised\Schedular;
use Unsupervised\Schedular\Auth\AccountPage;
use Unsupervised\Schedular\Auth\LoginPage;
use Unsupervised\Schedular\Auth\RegistrationPage;
use Unsupervised\Schedular\Booking\BookingPage;
@@ -18,6 +19,7 @@ class ShortcodeRegistrar {
private RegistrationPage $registrationPage,
private GroupClassPage $groupClassPage,
private FamilyPage $familyPage,
private AccountPage $accountPage,
) {}
public function register(): void {
@@ -26,6 +28,7 @@ class ShortcodeRegistrar {
add_shortcode( 'us_student_register', self::shortcode( [ $this->registrationPage, 'render' ] ) );
add_shortcode( 'us_group_classes', self::shortcode( [ $this->groupClassPage, 'render' ] ) );
add_shortcode( 'us_family', self::shortcode( [ $this->familyPage, 'render' ] ) );
add_shortcode( 'us_account', self::shortcode( [ $this->accountPage, 'render' ] ) );
// Process registration submissions before output so the invite branch's
// auth cookie is actually sent (render() runs too late, during the_content).
add_action( 'template_redirect', [ $this->registrationPage, 'maybeHandleSubmit' ] );
+38
View File
@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
if (! defined('ABSPATH')) {
exit;
}
/**
* @var string $name Display name of the signed-in visitor.
* @var string $email Their account email.
* @var list<string> $students Names this account books for, excluding themselves; empty for a plain student account.
* @var string $logoutUrl Nonced sign-out URL, already carrying its redirect.
*/
?>
<div class="us-account">
<p class="us-account-who">
<span class="us-account-name"><?php echo esc_html($name); ?></span>
<?php if ($email !== '') : ?>
<span class="us-account-email"><?php echo esc_html($email); ?></span>
<?php endif; ?>
</p>
<?php if (! empty($students)) : ?>
<p class="us-account-students">
<?php
printf(
/* translators: %s: comma-separated list of the students this account books for. */
esc_html__('Booking for %s', 'unsupervised-schedular'),
esc_html(implode(', ', $students))
);
?>
</p>
<?php endif; ?>
<p class="us-account-actions">
<a class="us-account-signout" href="<?php echo esc_url($logoutUrl); ?>"><?php esc_html_e('Sign out', 'unsupervised-schedular'); ?></a>
</p>
</div>
+158
View File
@@ -0,0 +1,158 @@
<?php
declare(strict_types=1);
namespace Unsupervised\Schedular\Tests\Unit\Auth;
use Brain\Monkey\Functions;
use Mockery;
use Unsupervised\Schedular\Auth\AccountPage;
use Unsupervised\Schedular\Guardian\GuardianService;
use Unsupervised\Schedular\Tests\Unit\TestCase;
class AccountPageTest extends TestCase
{
private GuardianService&Mockery\MockInterface $guardians;
private AccountPage $page;
protected function setUp(): void
{
parent::setUp();
$this->guardians = Mockery::mock(GuardianService::class);
$this->page = new AccountPage($this->guardians);
Functions\when('is_user_logged_in')->justReturn(true);
Functions\when('get_current_user_id')->justReturn(5);
Functions\when('wp_enqueue_style')->justReturn(null);
Functions\when('get_permalink')->alias(
static fn (int $id = 0): string => $id > 0
? 'https://studio.test/sign-in/'
: 'https://studio.test/current/'
);
Functions\when('wp_logout_url')->alias(
static fn (string $redirect): string => 'https://studio.test/wp-login.php?action=logout&redirect_to=' . rawurlencode($redirect)
);
Functions\when('wp_get_current_user')->justReturn($this->user('Grace', 'Hopper', '[email protected]'));
}
private function user(string $first, string $last, string $email): \WP_User
{
$user = Mockery::mock(\WP_User::class);
$user->ID = 5;
$user->first_name = $first;
$user->last_name = $last;
$user->nickname = '';
$user->user_email = $email;
return $user;
}
/** @param list<array{id: int, name: string, is_self: bool}> $students */
private function bookable(array $students): void
{
$this->guardians->shouldReceive('bookableStudents')->with(5)->andReturn($students);
}
public function testShowsTheSignedInNameAndEmail(): void
{
$this->bookable([['id' => 5, 'name' => 'Grace Hopper', 'is_self' => true]]);
$html = $this->page->render([]);
self::assertStringContainsString('Grace Hopper', $html);
self::assertStringContainsString('[email protected]', $html);
self::assertStringContainsString('Sign out', $html);
}
public function testNamesTheStudentsTheAccountBooksFor(): void
{
$this->bookable([
['id' => 42, 'name' => 'Ada', 'is_self' => false],
['id' => 43, 'name' => 'Alan', 'is_self' => false],
['id' => 5, 'name' => 'Grace Hopper', 'is_self' => true],
]);
self::assertStringContainsString('Booking for Ada, Alan', $this->page->render([]));
}
/**
* An account that only books for itself has nothing to add — "Booking for
* Grace Hopper" under "Grace Hopper" is noise.
*/
public function testSaysNothingAboutStudentsOnAPlainAccount(): void
{
$this->bookable([['id' => 5, 'name' => 'Grace Hopper', 'is_self' => true]]);
self::assertStringNotContainsString('Booking for', $this->page->render([]));
}
public function testSigningOutReturnsToTheConfiguredLoginPage(): void
{
$this->bookable([['id' => 5, 'name' => 'Grace Hopper', 'is_self' => true]]);
self::assertStringContainsString(
rawurlencode('https://studio.test/sign-in/'),
$this->page->render(['loginPageId' => 9])
);
}
/**
* With no page chosen, signing out from a header link should leave the
* visitor where they were rather than navigating them somewhere.
*/
public function testSigningOutReturnsToTheCurrentPageWhenNoLoginPageIsSet(): void
{
$this->bookable([['id' => 5, 'name' => 'Grace Hopper', 'is_self' => true]]);
self::assertStringContainsString(
rawurlencode('https://studio.test/current/'),
$this->page->render([])
);
}
public function testTheShortcodeAttributeNameIsAccepted(): void
{
$this->bookable([['id' => 5, 'name' => 'Grace Hopper', 'is_self' => true]]);
self::assertStringContainsString(
rawurlencode('https://studio.test/sign-in/'),
$this->page->render(['login_page_id' => 9])
);
}
/**
* A block whose whole job is "you are signed in as X" has nothing to say to
* a stranger, and a bare notice in a site header cannot be acted on.
*/
public function testRendersNothingForASignedOutVisitorWithNoLoginPage(): void
{
Functions\when('is_user_logged_in')->justReturn(false);
$this->guardians->shouldNotReceive('bookableStudents');
self::assertSame('', $this->page->render([]));
}
public function testOffersASignInLinkToASignedOutVisitorWhenAPageIsChosen(): void
{
Functions\when('is_user_logged_in')->justReturn(false);
$this->guardians->shouldNotReceive('bookableStudents');
$html = $this->page->render(['loginPageId' => 9]);
self::assertStringContainsString('https://studio.test/sign-in/', $html);
self::assertStringContainsString('Sign in', $html);
self::assertStringNotContainsString('Sign out', $html);
}
/**
* A page can be deleted after it has been chosen in the block, which
* get_permalink() reports as false.
*/
public function testTreatsADeletedLoginPageAsNoneChosen(): void
{
Functions\when('is_user_logged_in')->justReturn(false);
Functions\when('get_permalink')->justReturn(false);
self::assertSame('', $this->page->render(['loginPageId' => 9]));
}
}
+6
View File
@@ -6,6 +6,7 @@ namespace Unsupervised\Schedular\Tests\Unit;
use Brain\Monkey\Actions;
use Brain\Monkey\Functions;
use Mockery;
use Unsupervised\Schedular\Auth\AccountPage;
use Unsupervised\Schedular\Auth\LoginPage;
use Unsupervised\Schedular\Auth\RegistrationPage;
use Unsupervised\Schedular\BlockRegistrar;
@@ -43,6 +44,7 @@ class BlockRegistrarTest extends TestCase
private RegistrationPage&Mockery\MockInterface $registrationPage;
private GroupClassPage&Mockery\MockInterface $groupClassPage;
private FamilyPage&Mockery\MockInterface $familyPage;
private AccountPage&Mockery\MockInterface $accountPage;
private TestableBlockRegistrar $registrar;
protected function setUp(): void
@@ -54,6 +56,7 @@ class BlockRegistrarTest extends TestCase
$this->registrationPage = Mockery::mock(RegistrationPage::class);
$this->groupClassPage = Mockery::mock(GroupClassPage::class);
$this->familyPage = Mockery::mock(FamilyPage::class);
$this->accountPage = Mockery::mock(AccountPage::class);
// Most requests are not a just-finished registration; the tests that
// exercise that path override this.
@@ -67,6 +70,7 @@ class BlockRegistrarTest extends TestCase
$this->registrationPage,
$this->groupClassPage,
$this->familyPage,
$this->accountPage,
);
}
@@ -116,6 +120,7 @@ class BlockRegistrarTest extends TestCase
'us-scheduler/student-register',
'us-scheduler/group-classes',
'us-scheduler/family',
'us-scheduler/account',
],
array_keys($registered)
);
@@ -213,6 +218,7 @@ class BlockRegistrarTest extends TestCase
$this->registrationPage,
$this->groupClassPage,
$this->familyPage,
$this->accountPage,
);
$this->bookingPage->shouldReceive('render')->once()->with([])->andReturn('live');
+5 -1
View File
@@ -6,6 +6,7 @@ namespace Unsupervised\Schedular\Tests\Unit;
use Brain\Monkey\Actions;
use Brain\Monkey\Functions;
use Mockery;
use Unsupervised\Schedular\Auth\AccountPage;
use Unsupervised\Schedular\Auth\LoginPage;
use Unsupervised\Schedular\Auth\RegistrationPage;
use Unsupervised\Schedular\Booking\BookingPage;
@@ -20,6 +21,7 @@ class ShortcodeRegistrarTest extends TestCase
private RegistrationPage&Mockery\MockInterface $registrationPage;
private GroupClassPage&Mockery\MockInterface $groupClassPage;
private FamilyPage&Mockery\MockInterface $familyPage;
private AccountPage&Mockery\MockInterface $accountPage;
private ShortcodeRegistrar $registrar;
/** @var array<string, callable> */
@@ -37,6 +39,7 @@ class ShortcodeRegistrarTest extends TestCase
$this->registrationPage = Mockery::mock(RegistrationPage::class);
$this->groupClassPage = Mockery::mock(GroupClassPage::class);
$this->familyPage = Mockery::mock(FamilyPage::class);
$this->accountPage = Mockery::mock(AccountPage::class);
$this->registrar = new ShortcodeRegistrar(
$this->bookingPage,
@@ -44,6 +47,7 @@ class ShortcodeRegistrarTest extends TestCase
$this->registrationPage,
$this->groupClassPage,
$this->familyPage,
$this->accountPage,
);
$shortcodes = &$this->shortcodes;
@@ -66,7 +70,7 @@ class ShortcodeRegistrarTest extends TestCase
$this->registrar->register();
self::assertSame(
['us_booking', 'us_student_login', 'us_student_register', 'us_group_classes', 'us_family'],
['us_booking', 'us_student_login', 'us_student_register', 'us_group_classes', 'us_family', 'us_account'],
array_keys($this->shortcodes)
);
}