fix(core,basic): 검색 봇 화면 렌더러 패리티 결손 일괄 수정
일반 화면(React)과 봇 화면(PHP)은 같은 레이아웃을 각각 렌더하는데 봇 화면 쪽 지원 범위가 뒤처져, 확장이 교체한 본문이 통째로 빈 채 나갔다 (공개 이슈 ). 같은 결손 계열을 전수 조사해 함께 닫는다. - 확장 주입 props 를 렌더 진입 시점에 해석해 자손 전체에 상속 → 게시글·답글 원글·댓글·페이지·상품 설명 5개 지점 복구 - 사용자 작성 HTML 정화기 신설 — isHtml 판정에 따라 이스케이프/정화. 미정화 상태에서 봇 경로로 저장형 스크립트가 실제 실행됐다 - 노드 키 패리티: conditions / type:iterator / responsive 매칭 규칙 / children 문자열 / text 우선순위 / $t:defer / 레이아웃 초기 상태 - 표현식: 단일 바인딩 판정 교체, ||·&& 를 값 반환(JS 시맨틱)으로, 비교식이 raw 경로에서 null 이 되던 문제 - 데이터소스: 엔드포인트 표현식 전면 해석 + 레이아웃 8곳 선언 보강 - 봇 페이지 캐시 1회 전량 무효화 업그레이드 스텝 지원 범위 SSoT 표를 문서에 고정하고, 한쪽만 고치는 것을 막는 검사 룰과 레이아웃 전수 순회 테스트로 잠갔다.
This commit is contained in:
@@ -462,4 +462,120 @@ class DataSourceResolverTest extends TestCase
|
||||
&& str_contains($request->url(), 'page=3');
|
||||
});
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 엔드포인트 표현식 — route 외 컨텍스트 (query / _global)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* 엔드포인트 안의 {{query.xxx}} 표현식이 쿼리 파라미터로 치환됩니다.
|
||||
*/
|
||||
public function test_endpoint_resolves_query_expression(): void
|
||||
{
|
||||
Http::fake(['*' => Http::response(['data' => []], 200)]);
|
||||
|
||||
$dataSources = [
|
||||
['id' => 'searchResults', 'endpoint' => '/api/search?q={{query?.q}}', 'method' => 'GET'],
|
||||
];
|
||||
|
||||
$this->resolver->resolve($dataSources, ['searchResults'], [], 'ko', ['q' => '검색어']);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
return str_contains(urldecode($request->url()), 'q=검색어');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔드포인트 안의 {{_global.xxx}} 표현식이 전달된 컨텍스트로 치환됩니다.
|
||||
*/
|
||||
public function test_endpoint_resolves_global_expression(): void
|
||||
{
|
||||
Http::fake(['*' => Http::response(['data' => []], 200)]);
|
||||
|
||||
$dataSources = [
|
||||
[
|
||||
'id' => 'searchResults',
|
||||
'endpoint' => "/api/search?type={{_global.searchActiveTab ?? 'all'}}&page={{_global.searchPage ?? 1}}",
|
||||
'method' => 'GET',
|
||||
],
|
||||
];
|
||||
|
||||
$this->resolver->resolve(
|
||||
$dataSources,
|
||||
['searchResults'],
|
||||
[],
|
||||
'ko',
|
||||
[],
|
||||
['_global' => ['searchActiveTab' => 'products', 'searchPage' => 2]]
|
||||
);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
return str_contains($request->url(), 'type=products')
|
||||
&& str_contains($request->url(), 'page=2');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 전역 컨텍스트가 없으면 엔드포인트의 ?? 기본값이 적용됩니다.
|
||||
*/
|
||||
public function test_endpoint_global_expression_falls_back_to_default(): void
|
||||
{
|
||||
Http::fake(['*' => Http::response(['data' => []], 200)]);
|
||||
|
||||
$dataSources = [
|
||||
[
|
||||
'id' => 'searchResults',
|
||||
'endpoint' => "/api/search?type={{_global.searchActiveTab ?? 'all'}}",
|
||||
'method' => 'GET',
|
||||
],
|
||||
];
|
||||
|
||||
$this->resolver->resolve($dataSources, ['searchResults'], [], 'ko');
|
||||
|
||||
Http::assertSent(fn ($request) => str_contains($request->url(), 'type=all'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔드포인트에 표현식이 없으면 원본 그대로 사용됩니다 (회귀 방지).
|
||||
*/
|
||||
public function test_endpoint_without_expression_is_unchanged(): void
|
||||
{
|
||||
Http::fake(['*' => Http::response(['data' => []], 200)]);
|
||||
|
||||
$dataSources = [
|
||||
['id' => 'categories', 'endpoint' => '/api/categories', 'method' => 'GET'],
|
||||
];
|
||||
|
||||
$this->resolver->resolve($dataSources, ['categories'], [], 'ko');
|
||||
|
||||
Http::assertSent(fn ($request) => str_ends_with($request->url(), '/api/categories'));
|
||||
}
|
||||
|
||||
/**
|
||||
* params 표현식에서도 _global 컨텍스트를 참조할 수 있습니다.
|
||||
*/
|
||||
public function test_params_resolve_global_expression(): void
|
||||
{
|
||||
Http::fake(['*' => Http::response(['data' => []], 200)]);
|
||||
|
||||
$dataSources = [
|
||||
[
|
||||
'id' => 'products',
|
||||
'endpoint' => '/api/products',
|
||||
'method' => 'GET',
|
||||
'params' => ['currency' => "{{_global.preferredCurrency ?? 'KRW'}}"],
|
||||
],
|
||||
];
|
||||
|
||||
$this->resolver->resolve(
|
||||
$dataSources,
|
||||
['products'],
|
||||
[],
|
||||
'ko',
|
||||
[],
|
||||
['_global' => ['preferredCurrency' => 'USD']]
|
||||
);
|
||||
|
||||
Http::assertSent(fn ($request) => str_contains($request->url(), 'currency=USD'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user