fixed routing
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
latest: 2026.07.08
|
||||
|
||||
releases:
|
||||
2026.07.08:
|
||||
date: 2026-07-08
|
||||
changes:
|
||||
- Hardened platform company creation with unique slug generation for repeated browser-test runs.
|
||||
- Added deterministic Dusk synchronisation for the inline company creation form.
|
||||
@@ -24,5 +24,7 @@
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="SESSION_SECURE_COOKIE" value="false"/>
|
||||
<env name="DUSK_USE_EXTERNAL_SERVER" value="false"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
|
||||
@@ -45,7 +45,8 @@ class PlatformAdministrationBrowserTest extends DuskTestCase
|
||||
->type('billing_email', $billingEmail)
|
||||
->select('status', 'active')
|
||||
->press('Create')
|
||||
->pause(500);
|
||||
->waitForText('Company created.', 10)
|
||||
->waitForText($companyName, 10);
|
||||
});
|
||||
|
||||
$this->assertDatabaseHas('companies', [
|
||||
|
||||
+100
-40
@@ -63,7 +63,25 @@ abstract class DuskTestCase extends BaseTestCase
|
||||
|
||||
private static function configureDuskBaseUrl(): void
|
||||
{
|
||||
$url = rtrim((string) ($_ENV['DUSK_APP_URL'] ?? getenv('DUSK_APP_URL') ?: 'http://127.0.0.1:8000'), '/');
|
||||
// Do not trust an already-listening local server. In local Dusk runs it
|
||||
// may be Octane, Valet, or a stale `artisan serve` process using a
|
||||
// different database. Pick a free port for this PHPUnit run and start a
|
||||
// matching Laravel server below, unless explicitly told to use an
|
||||
// external server.
|
||||
$useExternalServer = filter_var(
|
||||
$_ENV['DUSK_USE_EXTERNAL_SERVER'] ?? getenv('DUSK_USE_EXTERNAL_SERVER') ?: false,
|
||||
FILTER_VALIDATE_BOOL,
|
||||
);
|
||||
|
||||
if ($useExternalServer) {
|
||||
$url = rtrim((string) ($_ENV['DUSK_APP_URL'] ?? getenv('DUSK_APP_URL') ?: 'http://127.0.0.1:8000'), '/');
|
||||
} else {
|
||||
$url = 'http://127.0.0.1:' . static::availablePort(8011, 8099);
|
||||
}
|
||||
|
||||
$_ENV['DUSK_APP_URL'] = $url;
|
||||
$_SERVER['DUSK_APP_URL'] = $url;
|
||||
putenv('DUSK_APP_URL=' . $url);
|
||||
|
||||
$_ENV['APP_URL'] = $url;
|
||||
$_SERVER['APP_URL'] = $url;
|
||||
@@ -83,28 +101,12 @@ abstract class DuskTestCase extends BaseTestCase
|
||||
$host = $parts['host'] ?? '127.0.0.1';
|
||||
$port = (int) ($parts['port'] ?? ($scheme === 'https' ? 443 : 80));
|
||||
|
||||
if (static::canConnect($host, $port)) {
|
||||
return;
|
||||
}
|
||||
$useExternalServer = filter_var(
|
||||
$_ENV['DUSK_USE_EXTERNAL_SERVER'] ?? getenv('DUSK_USE_EXTERNAL_SERVER') ?: false,
|
||||
FILTER_VALIDATE_BOOL,
|
||||
);
|
||||
|
||||
// Dusk should be deterministic in local/CI runs. If no reachable app
|
||||
// server is already running, start Laravel's built-in server for the
|
||||
// browser suite instead of failing every test with ERR_CONNECTION_REFUSED.
|
||||
if (! in_array($host, ['127.0.0.1', 'localhost'], true)) {
|
||||
$fallbackUrl = 'http://127.0.0.1:8000';
|
||||
$_ENV['APP_URL'] = $fallbackUrl;
|
||||
$_SERVER['APP_URL'] = $fallbackUrl;
|
||||
putenv('APP_URL=' . $fallbackUrl);
|
||||
|
||||
if (property_exists(BaseTestCase::class, 'baseUrl')) {
|
||||
static::$baseUrl = $fallbackUrl;
|
||||
}
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$port = 8000;
|
||||
}
|
||||
|
||||
if (static::canConnect($host, $port)) {
|
||||
if ($useExternalServer && static::canConnect($host, $port)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,15 +123,79 @@ abstract class DuskTestCase extends BaseTestCase
|
||||
@mkdir(dirname($logPath), 0775, true);
|
||||
}
|
||||
|
||||
$php = escapeshellarg(PHP_BINARY);
|
||||
$artisan = escapeshellarg($root . '/artisan');
|
||||
$hostArg = escapeshellarg($host);
|
||||
$portArg = (string) $port;
|
||||
$log = escapeshellarg($logPath);
|
||||
$command = sprintf(
|
||||
'%s %s serve --host=%s --port=%d',
|
||||
escapeshellarg(PHP_BINARY),
|
||||
escapeshellarg($root . '/artisan'),
|
||||
escapeshellarg($host),
|
||||
$port,
|
||||
);
|
||||
|
||||
$command = "{$php} {$artisan} serve --host={$hostArg} --port={$portArg} > {$log} 2>&1";
|
||||
$descriptors = [
|
||||
0 => ['pipe', 'r'],
|
||||
1 => ['file', $logPath, 'a'],
|
||||
2 => ['file', $logPath, 'a'],
|
||||
];
|
||||
|
||||
self::$laravelServerProcess = proc_open($command, [], $pipes, $root);
|
||||
$env = static::scalarEnvironment([
|
||||
...getenv(),
|
||||
...$_SERVER,
|
||||
...$_ENV,
|
||||
'APP_ENV' => $_ENV['APP_ENV'] ?? 'dusk',
|
||||
'APP_URL' => $_ENV['APP_URL'] ?? "http://{$host}:{$port}",
|
||||
'DUSK_APP_URL' => $_ENV['DUSK_APP_URL'] ?? "http://{$host}:{$port}",
|
||||
'CACHE_STORE' => $_ENV['CACHE_STORE'] ?? 'array',
|
||||
'QUEUE_CONNECTION' => $_ENV['QUEUE_CONNECTION'] ?? 'sync',
|
||||
'MAIL_MAILER' => $_ENV['MAIL_MAILER'] ?? 'array',
|
||||
]);
|
||||
|
||||
self::$laravelServerProcess = proc_open($command, $descriptors, $pipes, $root, $env);
|
||||
|
||||
if (isset($pipes[0]) && is_resource($pipes[0])) {
|
||||
fclose($pipes[0]);
|
||||
}
|
||||
|
||||
if (! is_resource(self::$laravelServerProcess)) {
|
||||
throw new \RuntimeException('Unable to start Laravel Dusk application server. Check storage/logs/dusk-server.log.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $environment
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private static function scalarEnvironment(array $environment): array
|
||||
{
|
||||
$filtered = [];
|
||||
|
||||
foreach ($environment as $key => $value) {
|
||||
if (! is_string($key) || $key === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_bool($value)) {
|
||||
$filtered[$key] = $value ? 'true' : 'false';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_scalar($value) || $value === null) {
|
||||
$filtered[$key] = (string) $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
private static function availablePort(int $from, int $to): int
|
||||
{
|
||||
for ($port = $from; $port <= $to; $port++) {
|
||||
if (! static::canConnect('127.0.0.1', $port)) {
|
||||
return $port;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException("No free TCP port available between {$from} and {$to} for Dusk.");
|
||||
}
|
||||
|
||||
private static function canConnect(string $host, int $port): bool
|
||||
@@ -194,17 +260,11 @@ abstract class DuskTestCase extends BaseTestCase
|
||||
},
|
||||
));
|
||||
|
||||
usort($candidates, static function (string $left, string $right): int {
|
||||
$score = static fn (string $path): int => str_contains($path, 'mac-arm64') ? 0
|
||||
: (str_contains($path, 'mac-arm') ? 1
|
||||
: (str_contains($path, 'mac') ? 2 : 3));
|
||||
|
||||
return $score($left) <=> $score($right);
|
||||
});
|
||||
|
||||
if ($candidates !== []) {
|
||||
@copy($candidates[0], $expected);
|
||||
@chmod($expected, 0755);
|
||||
if ($candidates === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy($candidates[0], $expected);
|
||||
@chmod($expected, 0755);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user