| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- <?php
- /**
- * Interface sounds (Cuelume, plugins_public/cuelume): Settings > Sounds (BxDolSounds) decides where they play and how,
- * form controls and tab menus carry the data-cuelume-* attributes its bind() plays, and the visitor's Sounds control
- * follows the settings.
- */
- class BxBaseInterfaceSoundsTest extends BxDolTestCase
- {
- private function withOption(string $sName, string $sValue, callable $fTest)
- {
- $sPrior = getParam($sName);
- setParam($sName, $sValue);
- try {
- return $fTest();
- }
- finally {
- setParam($sName, $sPrior);
- }
- }
- private function callProtected($oObject, string $sMethod, array $aArgs = [])
- {
- $oMethod = new ReflectionMethod($oObject, $sMethod);
- return $oMethod->invokeArgs($oObject, $aArgs);
- }
- private function withOptions(array $aOptions, callable $fTest)
- {
- if (!$aOptions)
- return $fTest();
- $sName = array_key_first($aOptions);
- $sValue = $aOptions[$sName];
- unset($aOptions[$sName]);
- return $this->withOption($sName, $sValue, fn() => $this->withOptions($aOptions, $fTest));
- }
- public function testHeadInjectionFollowsTheSitePlatform(): void
- {
- $oFunctions = BxTemplFunctions::getInstance();
- $sOn = $this->withOption('sys_sounds_platforms', 'site,ios', fn() => $this->callProtected($oFunctions, 'getInjHeadSounds'));
- $this->assertStringContainsString("bx_sound_init('" . BX_DOL_URL_PLUGINS_PUBLIC . "cuelume/cuelume.min.js', {", $sOn);
- $this->assertStringContainsString('"on":true', $sOn);
- $this->assertStringNotContainsString('"platforms"', $sOn);
- $sOff = $this->withOption('sys_sounds_platforms', 'studio,neo_web', fn() => $this->callProtected($oFunctions, 'getInjHeadSounds'));
- $this->assertSame('', $sOff);
- }
- public function testStudioKeepsItsPreviewsWhileSilent(): void
- {
- $oFunctions = BxTemplStudioFunctions::getInstance();
- $sOff = $this->withOption('sys_sounds_platforms', 'site', fn() => $this->callProtected($oFunctions, 'getInjHeadSounds'));
- $this->assertStringContainsString('bx_sound_init(', $sOff);
- $this->assertStringContainsString('"on":false', $sOff);
- $sOn = $this->withOption('sys_sounds_platforms', 'studio', fn() => $this->callProtected($oFunctions, 'getInjHeadSounds'));
- $this->assertStringContainsString('"on":true', $sOn);
- }
- public function testConfigListsOnlyWhatDiffersFromTheMainSet(): void
- {
- $aConfig = $this->withOptions([
- 'sys_sounds_platforms' => 'ios,site,nowhere',
- 'sys_sounds_level' => 'loud',
- 'sys_sounds_set' => 'mech',
- 'sys_sounds_volume' => '50',
- 'sys_sounds_buttons' => 'off',
- 'sys_sounds_choices' => 'mech',
- 'sys_sounds_reactions' => 'bubble',
- 'sys_sounds_menus' => 'nonsense',
- 'sys_sounds_navigation' => '',
- ], fn() => BxDolSounds::getInstance()->getConfig());
- $this->assertSame(['site', 'ios'], $aConfig['platforms']);
- $this->assertSame('full', $aConfig['level'], 'An unknown level starts people at full.');
- $this->assertSame('mech', $aConfig['set']);
- $this->assertSame(0.5, $aConfig['volume']);
- $this->assertSame(['buttons' => 'off', 'reactions' => 'bubble'], (array)$aConfig['groups']);
- $this->assertSame('{}', json_encode($this->withOptions(['sys_sounds_buttons' => '', 'sys_sounds_reactions' => ''], fn() => BxDolSounds::getInstance()->getConfig()['groups'])), 'Apps get an object, not a list.');
- }
- public function testEachKindOfActionOffersTheMainSetEverySetAndSilence(): void
- {
- $aValues = BxDolService::call('system', 'get_options_sounds_group', [], 'TemplServices');
- $this->assertSame(array_merge([''], BxDolSounds::SETS, ['off']), array_map('strval', array_keys($aValues)));
- $this->assertSame([100, 75, 50, 25], array_keys(BxDolService::call('system', 'get_options_sounds_volume', [], 'TemplServices')));
- }
- public function testSoundsSelectsPreviewInStudio(): void
- {
- $oOptions = new BxTemplStudioOptions('system', 'sounds');
- $aSelect = ['name' => 'sys_sounds_reactions', 'type' => 'select', 'caption' => '', 'info' => '', 'value' => '', 'extra' => 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:24:"get_options_sounds_group";s:5:"class";s:13:"TemplServices";}'];
- $aField = $this->callProtected($oOptions, 'field', [$aSelect, []]);
- $this->assertSame('bx_sound_preview(this)', $aField['attrs']['onchange']);
- $this->assertSame('reactions', $aField['attrs']['data-bx-sound-option']);
- $aOther = $this->callProtected($oOptions, 'field', [array_merge($aSelect, ['name' => 'sys_vote_reactions_mode', 'extra' => 'a,b']), []]);
- $this->assertArrayNotHasKey('onchange', $aOther['attrs']);
- }
- private function genInput(array $aInput): string
- {
- $oForm = new BxTemplFormView(['form_attrs' => ['id' => 'bx-sounds-test-form', 'method' => 'post'], 'inputs' => []]);
- return $oForm->genInput($aInput);
- }
- public function testSubmitTapsAndOtherButtonsTapSubtly(): void
- {
- $sSubmit = $this->genInput(['type' => 'submit', 'name' => 'save', 'value' => 'Save']);
- $this->assertStringContainsString('data-cuelume-tap=""', $sSubmit);
- $this->assertStringNotContainsString('data-cuelume-emphasis', $sSubmit);
- $sButton = $this->genInput(['type' => 'button', 'name' => 'more', 'value' => 'More']);
- $this->assertStringContainsString('data-cuelume-tap=""', $sButton);
- $this->assertStringContainsString('data-cuelume-emphasis="subtle"', $sButton);
- }
- public function testCheckboxTogglesAndRadioSelects(): void
- {
- $this->assertStringContainsString('data-cuelume-toggle=""', $this->genInput(['type' => 'checkbox', 'name' => 'agree', 'value' => '1']));
- $this->assertStringContainsString('data-cuelume-select=""', $this->genInput(['type' => 'radio', 'name' => 'pick', 'value' => '1']));
- }
- public function testSwitcherTogglesFromItsButtonOnly(): void
- {
- $sSwitcher = $this->genInput(['type' => 'switcher', 'name' => 'active', 'value' => '1', 'checked' => true]);
- // The visible button toggles; the hidden checkbox behind it must not sound a second time.
- $this->assertSame(1, substr_count($sSwitcher, 'data-cuelume-toggle'));
- $this->assertMatchesRegularExpression('/<button[^>]*role="switch"[^>]*data-cuelume-toggle/', $sSwitcher);
- }
- public function testFieldKeepsTheCueItPicked(): void
- {
- $sButton = $this->genInput(['type' => 'submit', 'name' => 'delete', 'value' => 'Delete', 'attrs' => ['data-cuelume-close' => '', 'data-cuelume-emphasis' => 'strong']]);
- $this->assertStringContainsString('data-cuelume-close=""', $sButton);
- $this->assertStringContainsString('data-cuelume-emphasis="strong"', $sButton);
- $this->assertStringNotContainsString('data-cuelume-tap', $sButton);
- }
- private function menuCode(string $sTemplate): string
- {
- $aItem = ['active' => 1, 'visible_for_levels' => 2147483647, 'target' => '', 'onclick' => '', 'icon' => '', 'addon' => '', 'submenu_object' => ''];
- $oMenu = new BxTemplMenu([
- 'object' => 'bx_sounds_test_menu',
- 'template' => $sTemplate,
- 'menu_items' => [
- array_merge($aItem, ['id' => 'latest', 'name' => 'latest', 'title' => 'Latest', 'link' => 'page.php?i=latest']),
- array_merge($aItem, ['id' => 'more-auto', 'name' => 'more-auto', 'title' => 'More', 'link' => 'javascript:void(0)']),
- ],
- ], BxDolTemplate::getInstance());
- return $oMenu->getCode();
- }
- public function testTabMenusSelectButNotTheirMoreItem(): void
- {
- $sTabs = $this->menuCode('menu_main_submenu.html');
- $this->assertSame(1, substr_count($sTabs, 'data-cuelume-select'), 'Only the tab selects; More opens a popup, which sounds itself.');
- $this->assertStringNotContainsString('data-cuelume-select', $this->menuCode('menu_vertical.html'));
- }
- public function testSoundsItemFollowsTheSitePlatform(): void
- {
- $oMenu = BxDolMenu::getObjectInstance('sys_account_notifications');
- if(!$oMenu)
- $this->markTestSkipped('sys_account_notifications is not installed.');
- $aItem = ['id' => 0, 'name' => 'sounds', 'module' => 'system', 'title' => '_sys_menu_item_title_sounds', 'link' => 'javascript:void(0);', 'onclick' => 'bx_sound_toggle(this);', 'target' => '', 'icon' => 'volume-up', 'addon' => '', 'submenu_object' => '', 'visible_for_levels' => 2147483647, 'active' => 1];
- $this->assertTrue($this->withOption('sys_sounds_platforms', 'site', fn() => $this->callProtected($oMenu, '_isVisible', [$aItem])));
- $this->assertFalse($this->withOption('sys_sounds_platforms', 'studio,ios', fn() => $this->callProtected($oMenu, '_isVisible', [$aItem])));
- $aRendered = $this->withOption('sys_sounds_platforms', 'site', fn() => $this->callProtected($oMenu, '_getMenuItem', [$aItem]));
- $this->assertIsArray($aRendered);
- $this->assertStringContainsString('role="button"', $aRendered['attrs'], 'Three levels: a button that steps through them, not a switch.');
- $this->assertStringContainsString('data-bx-sounds-switch="1"', $aRendered['attrs']);
- }
- public function testStudioSoundsItemIsALevelRadioGroup(): void
- {
- $oMenu = BxDolMenu::getObjectInstance('sys_studio_account_popup');
- if(!$oMenu)
- $this->markTestSkipped('sys_studio_account_popup is not installed.');
- $aItem = ['id' => 0, 'name' => 'sounds', 'module' => 'system', 'title' => '_sys_menu_item_title_sa_sounds', 'link' => 'javascript:void(0)', 'onclick' => 'bx_sound_toggle(this);', 'target' => '', 'icon' => 'ami-sounds.svg', 'addon' => '', 'submenu_object' => '', 'visible_for_levels' => 2147483647, 'active' => 1];
- $this->assertFalse($this->withOption('sys_sounds_platforms', 'site', fn() => $this->callProtected($oMenu, '_getMenuItem', [$aItem])));
- $aRendered = $this->withOption('sys_sounds_platforms', 'studio', fn() => $this->callProtected($oMenu, '_getMenuItem', [$aItem]));
- $this->assertTrue($aRendered['bx_if:show_sounds']['condition']);
- $this->assertFalse($aRendered['bx_if:show_button']['condition']);
- $this->assertSame(_t('_sys_txt_sounds_level_quiet'), $aRendered['bx_if:show_sounds']['content']['title_quiet']);
- }
- public function testStudioReplyCarriesItsCue(): void
- {
- if (!function_exists('bx_get_js_result'))
- require_once(BX_DIRECTORY_PATH_ROOT . 'studio/inc/utils.inc.php');
- $sReply = bx_get_js_result(['code' => 1, 'cue' => 'error', 'message' => 'x', 'translate' => false]);
- $this->assertStringContainsString('"cue":"error"', $sReply);
- $sReply = bx_get_js_result(['code' => 0, 'cue' => ['cue' => 'success', 'emphasis' => 'subtle']]);
- $this->assertStringContainsString('"cue":{"cue":"success","emphasis":"subtle"}', $sReply);
- }
- public function testFreshInstallDeclaresTheSoundsSection(): void
- {
- $sSql = file_get_contents(__DIR__ . '/../../../../install/sql/system.sql');
- $this->assertNotFalse($sSql);
- $this->assertStringContainsString("(@iTypeId, 'sounds', '_adm_stg_cpt_category_sounds', 0, 24)", $sSql);
- $this->assertStringContainsString("'sys_sounds_platforms', '_adm_stg_cpt_option_sys_sounds_platforms', '_adm_stg_inf_option_sys_sounds_platforms', 'site,studio,neo_web,ios,android', 'list',", $sSql);
- foreach (BxDolSounds::GROUPS as $sGroup)
- $this->assertMatchesRegularExpression("/\\(@iCategoryId, 'sys_sounds_" . $sGroup . "', '_adm_stg_cpt_option_sys_sounds_" . $sGroup . "', '_adm_stg_inf_option_sys_sounds_" . $sGroup . "', '', 'select',/", $sSql);
- $this->assertStringNotContainsString('sys_ui_sounds', $sSql);
- $this->assertStringContainsString("('sys_account_notifications', 'system', 'sounds',", $sSql);
- $this->assertStringContainsString("('sys_studio_account_popup', 'system', 'sounds',", $sSql);
- }
- }
|