Rumah > pembangunan bahagian belakang > tutorial php > Menggunakan selenium dengan phpunit

Menggunakan selenium dengan phpunit

Christopher Nolan
Lepaskan: 2025-02-17 08:31:09
asal
347 orang telah melayarinya

Menggunakan selenium dengan phpunit

Ujian adalah subjek yang sangat luas, sama ada ujian unit, ujian fungsional, ujian penerimaan, dan lain -lain. Dalam artikel ini, kita akan melihat bagaimana anda boleh melakukan ujian penerimaan menggunakan selenium. Saya akan menggunakan contoh praktikal untuk menggambarkan kes penggunaan sebenar. Saya akan mengandaikan bahawa anda sudah tahu bagaimana melakukan ujian unit menggunakan phpunit, atau sekurang -kurangnya anda memahami apa yang berlaku. Mari kita mulakan.

Takeaways Key Menggunakan selenium dengan phpunit

Selenium adalah alat untuk mengautomasikan ujian antara muka pengguna, yang membolehkan anda menyediakan ujian yang berinteraksi dengan aplikasi web anda sebagai pengguna. Ia berfungsi dengan menterjemahkan ujian ke dalam arahan dan lulusnya ke pelayan selenium, yang kemudiannya berinteraksi dengan pelayar web menggunakan API asli.

    phpunit, rangka kerja ujian unit untuk PHP, boleh digunakan bersamaan dengan selenium untuk ujian penerimaan. Ia menyediakan dua kelas untuk tujuan ini: phpunit_extensions_seleniumtestcase untuk selenium RC (kini ditolak) dan phpunit_extensions_selenium2testase untuk selenium webdriver.
  • Pembekal data dalam PHPUnit membolehkan pemakanan data tertentu ke dalam ujian tanpa pengalihan. Ini boleh digunakan bersamaan dengan Selenium untuk menguji bagaimana aplikasi web anda bertindak balas terhadap input yang berbeza.
  • Ujian Selenium boleh dijalankan pada pelayar yang berbeza, kerana Selenium menggunakan pendekatan pemandu di mana setiap vendor penyemak imbas menyediakan pemandu sendiri. Ini membolehkan ujian silang penyemak imbas komprehensif aplikasi web anda.
  • Apakah ujian penerimaan?
ujian penerimaan adalah proses menceritakan kisah pengguna melalui ujian, dan saya suka petikan ini untuk menerangkannya:

Ujian rasmi yang dijalankan untuk menentukan sama ada sistem memenuhi kriteria penerimaannya dan untuk membolehkan pelanggan menentukan sama ada atau tidak untuk menerima sistem tersebut.

Apa selenium?

Selenium adalah alat untuk mengautomasikan ujian antara muka pengguna. Ia membantu dengan menguji permohonan anda terhadap penyemak imbas. Proses ini boleh digambarkan seperti:

pergi ke halaman http://myapp.dev/videos.

    menegaskan halaman mengandungi senarai 20 video.
  • Klik nombor dua pada penomboran.
  • menegaskan halaman mengandungi senarai 20 video.
  • berhenti penyemak imbas.
  • anda mungkin tertanya -tanya: "Bagaimana ia memanipulasi laman web menggunakan ujian yang diterangkan?"
Jawapannya adalah "ia bergantung". Jika anda menggunakan Selenium RC (sebelum ini dinamakan Selenium 1), ia akan menyuntik kod JavaScript yang dihasilkan auto ke halaman untuk melakukan tindakan yang dikehendaki. Selenium RC ditutup dan hanya disokong dalam mod penyelenggaraan; Anda harus menggunakan selenium webdriver.

Apabila menggunakan selenium webdriver (selenium 2), ujian diterjemahkan ke dalam arahan dan dihantar ke pelayan Selenium (lebih lanjut mengenai itu dalam seketika), kemudian dihantar ke penyemak imbas menggunakan API Native Browser Web.

Persediaan Aplikasi

Kerana kita sebenarnya tidak mempunyai aplikasi untuk menguji, saya akan menggunakan halaman pendaftaran pengguna. Pengguna akan memasukkan maklumat peribadinya dan beberapa maklumat pengebilan. Sekiranya semuanya baik, halaman harus mengeluarkan semuanya baik!. Jika tidak, halaman akan menunjukkan borang langganan dengan senarai mesej ralat pengesahan.

Menggunakan selenium dengan phpunit

Kami akan mula menguji aplikasi kami menggunakan phpUnit dengan lanjutan selenium. Pastikan anda memasangnya menggunakan komposer sebelum memulakan.

<span>composer require --dev phpunit/phpunit
</span><span>composer require --dev phpunit/phpunit-selenium</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
kami berkata sebelum arahan itu dihantar ke pelayan Selenium, yang kemudiannya meneruskannya ke penyemak imbas. Kita perlu memuat turun pelayan Selenium, yang hanya boleh dilaksanakan oleh Java Archive. Pelayan boleh dijalankan menggunakan java -jar selenium-server-state- .jar. Oleh kerana kita akan menggunakannya dengan kerap, adalah idea yang baik untuk memindahkannya ke direktori bin dan membuat alias untuk itu di dalam .bashrc atau .zshrc.

<span>alias sserve="java -jar /usr/local/bin/selenium-server-standalone-<version>.jar"</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
phpunit dan selenium

PHPUnit menyokong kedua -dua Selenium RC dan WebDriver, dan ia menyediakan dua kelas untuk tujuan itu. PHPUNIT_EXTENSIONS_SELENUMTESTCASE digunakan untuk versi RC, dan phpunit_extensions_selenium2testase digunakan untuk versi webdriver. Oleh itu, ujian anda mesti melanjutkan salah satu daripada mereka untuk memulakan. Sila ingat bahawa versi RC sedang ditolak, jadi kami akan menggunakan WebDriver One dalam contoh kami di bawah.

<span>// tests/acceptance/UserSubscriptionTest.php
</span>
<span>class UserSubscriptionTest extends PHPUnit_Extensions_Selenium2TestCase
</span><span>{
</span>    <span>public function setUp()
</span>    <span>{
</span>        <span>$this->setHost('localhost');
</span>        <span>$this->setPort(4444);
</span>        <span>$this->setBrowserUrl('http://vaprobash.dev');
</span>        <span>$this->setBrowser('firefox');
</span>    <span>}
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Kaedah persediaan digunakan untuk menyediakan persekitaran ujian. Dalam kes ini, kami menggunakannya untuk memberitahu PHPUNIT di mana pelayan Selenium kami sedang berjalan, penyemak imbas apa yang akan kami gunakan dan URL aplikasi kami. Kaedah Sethost mungkir ke localhost dan kaedah setport mungkir kepada 4444, supaya mereka boleh ditinggalkan di sini. Walau bagaimanapun, ini boleh digunakan jika pelayan ujian anda berada di dalam mesin Windows yang menyokong Internet Explorer semasa anda menjalankan ujian anda dari mesin lain yang berbeza, dan lain -lain

Kaedah Tearown dipanggil apabila ujian dilakukan, dan ia digunakan untuk membersihkan panggung. Kami menggunakannya untuk menutup penyemak imbas dan menamatkan sesi semasa.

<span>public function tearDown()
</span><span>{
</span>    <span>$this->stop();
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Pembekal data

penyedia data PHPUnit membenarkan kami memberi makan ujian kami dengan data tertentu tanpa perlu melelehkannya. Anda boleh membaca lebih lanjut dalam dokumentasi.

<span>// tests/acceptance/UserSubscriptionTest.php
</span>
<span>class UserSubscriptionTest extends PHPUnit_Extensions_Selenium2TestCase
</span><span>{
</span>    <span>public function validInputsProvider()
</span>    <span>{
</span>        <span>$inputs[] = [
</span>            <span>[
</span>                <span>'username'              => 'younesrafie',
</span>                <span>'password'              => 'mypassword',
</span>                <span>'password_confirmation' => 'mypassword',
</span>                <span>'email'                 => 'mymail@gmail.com',
</span>                <span>'cardHolderName'        => 'RAFIE Younes',
</span>                <span>'cardNumber'            => '378282246310005',
</span>                <span>'billingAddress'        => 'Narjiss B Fez Morocco',
</span>                <span>'cvc'                   => '850',
</span>                <span>'expirationMonth'       => '01',
</span>                <span>'expirationYear'        => '2016',
</span>            <span>]
</span>        <span>];
</span>
        <span>return $inputs;
</span>    <span>}
</span>    
    <span>public static function invalidInputsProvider()
</span>    <span>{
</span>        <span>$inputs[] = [
</span>            <span>[
</span>                <span>'username'              => '@younesrafie',
</span>                <span>'password'              => 'mypassword',
</span>                <span>'password_confirmation' => 'mypassword',
</span>                <span>'email'                 => 'mymail@gmail.com',
</span>                <span>'cardHolderName'        => 'RAFIE Younes',
</span>                <span>'cardNumber'            => '378282246310005',
</span>                <span>'billingAddress'        => 'Narjiss B Fez Morocco',
</span>                <span>'cvc'                   => '850',
</span>                <span>'expirationMonth'       => '01',
</span>                <span>'expirationYear'        => '2016',
</span>            <span>],
</span>            <span>"Username must only contain alpha numeric characters and dashes."
</span>        <span>];
</span>        <span>// ...
</span>        
        <span>return $inputs;
</span>    <span>}
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
InvalidInputSprovider mengembalikan senarai input yang sah kecuali satu bidang, dan kami menyampaikan mesej ralat yang dijangkakan selepas pengesahan gagal.

bekerja dengan elemen dom

Satu tugas biasa apabila bekerja dengan laman web adalah pemilihan elemen. Pelanjutan Selenium PhPunit menyediakan API yang sangat bagus untuk itu. Anda boleh memilih elemen mengikut nama kelas, tag, nama, id, pemilih css, xpath, dan lain -lain. Kaedah ini akan mengembalikan contoh phpunit_extensions_selenium2testcase_element yang boleh anda gunakan untuk memilih elemen kanak -kanak lain, atribut, dan lain -lain. Anda juga boleh menetapkan atau mendapatkan elemen Nilai, kemas kini elemen CSS dan sekumpulan tugas umum yang lain. Untuk halaman kami, kami boleh melakukan sesuatu seperti yang berikut.

<span>composer require --dev phpunit/phpunit
</span><span>composer require --dev phpunit/phpunit-selenium</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Ujian ini akan memilih input nama pengguna dan menetapkan nilai, kemudian serahkan borang langganan. Kami boleh menambah pernyataan selepas itu untuk melihat sama ada tindak balas seperti yang diharapkan. Badan halaman akan mengandungi semuanya baik! Sekiranya pengesahan diluluskan.

<span>alias sserve="java -jar /usr/local/bin/selenium-server-standalone-<version>.jar"</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Penyedia data kami mengandungi nama input dan nilai yang sepadan. Kami akan membuat kaedah berasingan untuk mengendalikan mengisi input borang dan mengemukakan.

<span>// tests/acceptance/UserSubscriptionTest.php
</span>
<span>class UserSubscriptionTest extends PHPUnit_Extensions_Selenium2TestCase
</span><span>{
</span>    <span>public function setUp()
</span>    <span>{
</span>        <span>$this->setHost('localhost');
</span>        <span>$this->setPort(4444);
</span>        <span>$this->setBrowserUrl('http://vaprobash.dev');
</span>        <span>$this->setBrowser('firefox');
</span>    <span>}
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

penyerahan borang yang sah

Untuk menunjuk penyemak imbas ke halaman tertentu, kami menggunakan kaedah URL dari kelas phpunit_extensions_selenium2testase. URL adalah relatif kepada yang diberikan kepada kaedah setBrowserurl. Oleh itu, setelah menunjuk penyemak imbas ke halaman indeks yang kami isi dan serahkan borang, kemudian uji mesej kejayaan yang diharapkan.

<span>public function tearDown()
</span><span>{
</span>    <span>$this->stop();
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Dengan mengandaikan pelayan selenium anda sedang berjalan dan berjalan, teruskan dan jalankan ujian anda dengan ujian phpunit/penerimaan/userubscriptiontest.php. Ini akan mewujudkan sesi penyemak imbas baru dan mula mengisi borang. Kami mengharapkan segala -galanya untuk lulus dengan satu pernyataan yang berjaya.

Menggunakan selenium dengan phpunit

Beberapa ujian gagal, dan tempoh ujian terlalu pendek bagi kita untuk melihat apa yang berlaku. PHPUnit mempunyai keupayaan untuk menangkap tangkapan skrin ujian gagal menggunakan kaedah currentscreenshot yang mengembalikan imej gumpalan yang dapat kita simpan.

<span>// tests/acceptance/UserSubscriptionTest.php
</span>
<span>class UserSubscriptionTest extends PHPUnit_Extensions_Selenium2TestCase
</span><span>{
</span>    <span>public function validInputsProvider()
</span>    <span>{
</span>        <span>$inputs[] = [
</span>            <span>[
</span>                <span>'username'              => 'younesrafie',
</span>                <span>'password'              => 'mypassword',
</span>                <span>'password_confirmation' => 'mypassword',
</span>                <span>'email'                 => 'mymail@gmail.com',
</span>                <span>'cardHolderName'        => 'RAFIE Younes',
</span>                <span>'cardNumber'            => '378282246310005',
</span>                <span>'billingAddress'        => 'Narjiss B Fez Morocco',
</span>                <span>'cvc'                   => '850',
</span>                <span>'expirationMonth'       => '01',
</span>                <span>'expirationYear'        => '2016',
</span>            <span>]
</span>        <span>];
</span>
        <span>return $inputs;
</span>    <span>}
</span>    
    <span>public static function invalidInputsProvider()
</span>    <span>{
</span>        <span>$inputs[] = [
</span>            <span>[
</span>                <span>'username'              => '@younesrafie',
</span>                <span>'password'              => 'mypassword',
</span>                <span>'password_confirmation' => 'mypassword',
</span>                <span>'email'                 => 'mymail@gmail.com',
</span>                <span>'cardHolderName'        => 'RAFIE Younes',
</span>                <span>'cardNumber'            => '378282246310005',
</span>                <span>'billingAddress'        => 'Narjiss B Fez Morocco',
</span>                <span>'cvc'                   => '850',
</span>                <span>'expirationMonth'       => '01',
</span>                <span>'expirationYear'        => '2016',
</span>            <span>],
</span>            <span>"Username must only contain alpha numeric characters and dashes."
</span>        <span>];
</span>        <span>// ...
</span>        
        <span>return $inputs;
</span>    <span>}
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
penyerahan bentuk tidak sah

Penyerahan bentuk tidak sah hampir sama dengan kaedah sebelumnya. Kami mengisi input borang dan hantar. Kemudian, kami mengesahkan bahawa mesej ralat pengesahan adalah seperti yang diharapkan. Kami akan menggunakan InvalidInputSprovider yang saya sebutkan tadi.

<span>class UserSubscriptionTest extends PHPUnit_Extensions_Selenium2TestCase
</span><span>{
</span>    <span>public function testFormSubmissionWithUsername()
</span>    <span>{
</span>        <span>$this->byName('username')->value('younesrafie');
</span>        <span>$this->byId('subscriptionForm')->submit();
</span>    <span>}
</span><span>}</span>
Salin selepas log masuk
Kaedah BYCSSSSELECTOR membolehkan kami mengambil elemen dari halaman menggunakan pemilih CSS, dalam hal ini perenggan ralat. Kami menegaskan sama ada mesej ralat seperti yang diharapkan menggunakan medan mesej ralat dari kaedah penyedia data.

Borang kami hanya mengandungi interaksi asas seperti memilih elemen, menetapkan nilai, menyerahkan borang, dan lain -lain. Walau bagaimanapun, kami juga boleh menggunakan kaedah klik pada butang atau elemen pautan untuk mengesahkan bahawa halaman sasaran berfungsi seperti yang diharapkan.

menggunakan penyemak imbas lain

Kami menggunakan penyemak imbas Firefox untuk ujian kami. Walau bagaimanapun, kami mempunyai keupayaan untuk menggunakan pelayar lain juga. Selenium menggunakan pendekatan pemandu, di mana setiap vendor penyemak imbas berfungsi untuk menyediakan pemandu sendiri. Anda boleh menyemak senarai pemandu yang disokong dalam dokumentasi.

Untuk membolehkan penyemak imbas Chrome, anda perlu memuat turun Chromedriver dan menentukan laluan sebagai pilihan apabila melancarkan pelayan Selenium.

<span>composer require --dev phpunit/phpunit
</span><span>composer require --dev phpunit/phpunit-selenium</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
<span>alias sserve="java -jar /usr/local/bin/selenium-server-standalone-<version>.jar"</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Menggunakan selenium dengan phpunit

Adakah dokumen siap?

Jika kandungan halaman anda dimuatkan melalui Ajax, dan anda tidak mahu mencetuskan ujian secara langsung pada beban halaman, anda akan mahu menunggu sehingga halaman anda dimuatkan dan unsur -unsur anda hadir.

<span>// tests/acceptance/UserSubscriptionTest.php
</span>
<span>class UserSubscriptionTest extends PHPUnit_Extensions_Selenium2TestCase
</span><span>{
</span>    <span>public function setUp()
</span>    <span>{
</span>        <span>$this->setHost('localhost');
</span>        <span>$this->setPort(4444);
</span>        <span>$this->setBrowserUrl('http://vaprobash.dev');
</span>        <span>$this->setBrowser('firefox');
</span>    <span>}
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Fungsi panggil balik akan menunggu sehingga kami mengembalikan nilai yang tidak nol, dan akan tamat selepas dua saat dengan mesej ralat. Kaedah carian akan terus mencari elemen, tetapi jika anda ingin menentukan selang carian, anda boleh menggunakan kaedah yang tersirat.

<span>public function tearDown()
</span><span>{
</span>    <span>$this->stop();
</span><span>}</span>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Kesimpulan

Artikel ini adalah pengenalan ringkas untuk menggunakan Selenium dengan phpunit untuk ujian penerimaan. Secara umum, anda boleh menggunakan Selenium untuk apa -apa yang memerlukan automasi penyemak imbas. Sekiranya anda mempunyai komen atau soalan, pastikan anda menghantarnya di bawah dan saya akan melakukan yang terbaik untuk menjawabnya.

Soalan Lazim (Soalan Lazim) Mengenai Menggunakan Selenium dengan PHPUnit

Bagaimana saya memasang phpunit dan selenium webdriver dalam php?

Untuk memasang phpunit dan selenium webdriver dalam php, anda perlu menggunakan komposer, alat pengurusan ketergantungan untuk php. Pertama, pasang komposer jika anda belum melakukannya. Kemudian, jalankan perintah berikut di terminal anda untuk memasang phpunit: komposer memerlukan --peV phpunit/phpunit ^9. Untuk Selenium WebDriver, gunakan arahan: komposer memerlukan-PHP-webdriver/webdriver. Ini akan memasang kedua -dua phpunit dan selenium webdriver dalam projek php anda.

Bagaimana saya boleh menjalankan ujian phpunit dengan selenium?

Itu menggunakan selenium webdriver. Dalam kes ujian anda, anda boleh menggunakan arahan WebDriver untuk berinteraksi dengan penyemak imbas. Sebaik sahaja kes ujian anda siap, anda boleh menjalankannya menggunakan alat baris arahan phpunit. Cukup navigasi ke direktori projek anda di terminal dan jalankan arahan: phpUnit myest.php, di mana 'myTest.php' adalah nama fail ujian anda.

Bagaimana saya menggunakan pernyataan dalam phpunit dengan selenium?

Pernyataan digunakan dalam phpunit untuk mengesahkan bahawa keadaan tertentu adalah benar. Mereka adalah penting untuk menentukan sama ada ujian telah berlalu atau gagal. Dalam ujian phpunit dengan selenium, anda boleh menggunakan pernyataan untuk memeriksa keadaan elemen web. Sebagai contoh, anda boleh menegaskan bahawa elemen tertentu hadir, kelihatan, atau mengandungi teks tertentu. Untuk melakukan ini, anda boleh menggunakan kaedah menegaskan yang disediakan oleh phpunit, seperti assertequals, assertTrue, atau asse asseContains. PHPUnit dengan Selenium dilakukan menggunakan kaedah sesi WebDriver. Apabila anda membuat contoh baru WebDriver, sesi penyemak imbas baru dimulakan. Anda boleh berinteraksi dengan sesi ini menggunakan pelbagai kaedah, seperti menavigasi (), menyegarkan (), atau menutup (). Untuk mengakhiri sesi, anda boleh menggunakan kaedah berhenti (), yang akan menutup semua tingkap dan menamatkan sesi. Dalam phpunit dengan selenium boleh menjadi rumit kerana anda perlu menunggu panggilan AJAX selesai sebelum anda dapat berinteraksi dengan elemen yang dikemas kini. Selenium WebDriver menyediakan kelas WebDriverWait untuk tujuan ini. Anda boleh menggunakannya untuk menunggu keadaan tertentu menjadi kenyataan sebelum meneruskan. Sebagai contoh, anda boleh menunggu elemen dapat dilihat atau diklik. Safari, dan Internet Explorer. Untuk menjalankan ujian phpunit anda pada penyemak imbas yang berbeza, anda perlu membuat contoh baru WebDriver untuk penyemak imbas itu. Sebagai contoh, untuk menggunakan Firefox, anda akan membuat contoh FirefoxDriver baru. Kemudian, anda boleh menggunakan pemacu ini untuk menjalankan ujian anda.

Bagaimana saya mengendalikan bingkai dan iframes dalam phpunit dengan selenium? ) Kaedah WebDriver. Kaedah ini membolehkan anda menukar konteks ke bingkai yang berbeza atau iframe. Sebaik sahaja anda selesai berinteraksi dengan unsur-unsur di dalam bingkai, anda boleh beralih ke kandungan utama menggunakan switchto ()-> defaultContent () kaedah.

Bagaimana saya boleh mengambil tangkapan skrin dengan selenium dalam ujian phpunit?

Mengambil tangkapan skrin dengan selenium dalam ujian phpUnit boleh dilakukan dengan menggunakan kaedah penanda web. Kaedah ini mengambil tangkapan skrin tetingkap semasa dan mengembalikannya sebagai rentetan dalam format PNG. Anda kemudian boleh menyimpan rentetan ini ke fail untuk membuat tangkapan skrin.

Bagaimana saya mengendalikan kuki di phpunit dengan selenium?

Cookies boleh dikendalikan dalam phpUnit dengan selenium menggunakan kaedah Manage ()-> getCookies () Webdriver. Kaedah ini mengembalikan semua kuki sebagai array. Anda juga boleh menggunakan Urus ()-> addCookie (), mengurus ()-> deleteCookie (), dan mengurus ()-> deleteallCookies () kaedah untuk memanipulasi cookies. Selenium secara selari? Ini boleh dicapai menggunakan grid selenium, yang membolehkan anda menjalankan ujian pada pelbagai mesin dan pelayar serentak. Untuk menggunakan selenium grid, anda perlu menyediakan hab dan nod, dan kemudian mengkonfigurasi webdriver anda untuk menyambung ke hab.

Atas ialah kandungan terperinci Menggunakan selenium dengan phpunit. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan