DEV Community

Kay Gosho
Kay Gosho

Posted on

Multibyte text and Laravel testing

Problem

When I wrote test code in Laravel, I encountered a problem.

My API returns multibyte text.
By default, PHP's json_encode escapes multibyte text so my API returns like this:

curl localhost:8000/api/post/1

# Expected
{"title":"日本語"}

# Actual
{"title":"\u65e5\u672c\u8a9e"}
Enter fullscreen mode Exit fullscreen mode

Laravel's $response->assertSeeText('日本語') does not work because it compares UTF-8 decoded string.

Example

This test passes:

<?php

use App\User;
use Tests\TestCase;

class UserTest extends TestCase
{
    public function testCanCreateUser()
    {
        User::create([
            'name' => '太郎',
            'gender' => 'male',
        ]);
        $this->assertDatabaseHas('users', [
            'name' => '太郎',
            'gender' => 'male',
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

(TODO: In my case, I expected this test fail... but passed.)

This test, returns JSON API, fails:

<?php

use App\User;
use Tests\TestCase;

class UserTest extends TestCase
{
    public function testUserProfileApi()
    {
        $user = User::create([
            'name' => '太郎',
            'sex' => 'male',
        ]);
        $this->actingAs($user)
            ->get('/api/me')
            ->assertSeeText('太郎');
    }
}
Enter fullscreen mode Exit fullscreen mode

Reports the following error:

1) UserTest::testCanCreateUser
Failed asserting that '{"name":"\u592a\u90ce","sex":"male"}' contains "太郎".
Enter fullscreen mode Exit fullscreen mode

Certainly, the text "太郎" is escaped.

Solution

Simply, assert the result using json_encode.

<?php

use App\User;

//...
        $this->actingAs($user)
            ->get('/api/me')
            ->assertSeeText(json_encode('太郎'));
// ...
Enter fullscreen mode Exit fullscreen mode

You might wonder why I don't use utf8_encode, but in my case it failed.
Maybe that depends on php.ini.

There are other failing cases related to multibyte, in my case writing OAuth testing using mock object.
Then you can try e('太郎'). My problem was solved by this.

We can avoid using multibyte string in testing, but sometimes we need to test such strings.

Refs

I researched a lot of websites, including Chinese websites like 思否, finally found in Stack Overflow as usual.

https://stackoverflow.com/questions/49570725/laravel-5-assertseetext-and-html-entities

I sometimes run into Chinese articles when solving these multibyte problem.
I cannot understand accurately but by Kanji I can guess what they say.

Top comments (0)