Доволно долго бев во развој на предниот дел за да видам тренд низ годините: помлади програмери работат со нова парадигма на програмирање без да го разберат историскиот контекст на тоа. Се разбира, сосема е разбирливо да не се знае нешто. Мрежата е многу големо место со разновиден сет на вештини и специјалитети и не секогаш го знаеме она што не го знаеме. Учењето на ова поле е тековно патување наместо нешто што се случува еднаш и завршува. Конкретен случај: Некој од мојот тим праша дали е можно да се каже дали корисниците се оддалечуваат од одредена картичка во интерфејсот. Го посочив настанот на JavaScript пред да се вчита. Но, оние кои претходно се справиле со ова знаат дека ова е можно затоа што биле погодени со предупредувања за незачувани податоци на други сајтови, за кои пред симнувањето е типичен случај на употреба. Исто така, на мојот колега му ја посочив страницатаСкриј и видливостПромена на настани. Како знаев за тоа? Затоа што се појави во друг проект, а не затоа што го проучував кога првично учев JavaScript. Факт е дека модерните предни рамки стојат на рамениците на технолошките гиганти што им претходеа. Тие ги апстрактираат развојните практики, честопати за подобро искуство на програмерите што ја намалува, па дури и ја елиминира потребата да се знае или да се допре она што традиционално биле суштински концепти на предниот дел, кои веројатно секој треба да ги знае. Размислете за моделот на објект CSS (CSSOM). Може да очекувате дека секој што работи во CSS и JavaScript има многу практично CSSOM искуство, но тоа не секогаш ќе биде така. Имаше проект React за страница за е-трговија на која работев каде што требаше да вчитаме лист со стилови за моментално избраниот давател на плаќања. Проблемот беше што листот со стилови се вчитуваше на секоја страница кога беше навистина потребен само на одредена страница. Развивачот задолжен да го направи ова никогаш не вчитал лист со стилови динамично. Повторно, ова е сосема разбирливо кога React го апстрахира традиционалниот пристап по кој можеби сте посегнале. CSSOM веројатно не е нешто што ви треба во вашата секојдневна работа. Но, веројатно е дека ќе треба да комуницирате со него во одреден момент, дури и во еден случај. Овие искуства ме инспирираа да ја напишам оваа статија. Постојат многу постоечки веб-функции и технологии во дивината што никогаш нема да ги допрете директно во вашата секојдневна работа. Можеби сте прилично нови за веб-развој и едноставно не сте свесни за нив затоа што сте натопени во апстракцијата на одредена рамка која не бара од вас да ја знаете длабоко, па дури и воопшто. Зборувам конкретно за XML, за кој многумина од нас знаат дека е древен јазик кој не е целосно различен од HTML. Ова го кажувам поради неодамнешните дискусии за WHATWG кои сугерираат дека значителен дел од стекот XML познат како програмирање XSLT треба да се отстрани од прелистувачите. Ова е токму оној вид на постара, постоечка технологија што ја имавме со години што може да се користи за нешто толку практично како ситуацијата во CSSOM во која се наоѓаше мојот тим. Дали сте работеле со XSLT порано? Ајде да видиме дали многу се потпираме на оваа постара технологија и дали ќе ги искористиме нејзините карактеристики надвор од контекстот на XML за да се справиме со проблемите од реалниот свет денес. XPath: Централниот API Најважната XML технологија која е можеби најкорисната надвор од директната XML перспектива е XPath, јазик за пребарување кој ви овозможува да најдете кој било јазол или атрибут во дрвото за означување со еден корен елемент. Имам лична наклонетост кон XSLT, но тоа исто така се потпира на XPath, а личната наклонетост мора да се остави настрана во важноста на рангирањето. Аргументот за отстранување на XSLT не го спомнува XPath, па претпоставувам дека сè уште е дозволено. Тоа е добро затоа што XPath е централниот и најважниот API во овој пакет технологии, особено кога се обидувате да најдете нешто за користење надвор од нормалната употреба на XML. Тоа е важно затоа што, иако CSS селектори може да се користат за да се најдат повеќето елементи на вашата страница, тие не можат да ги најдат сите. Понатаму, CSS селектори не може да се користат за да се најде елемент врз основа на неговата моментална позиција во DOM. XPath може. Сега, некои од вас што го читаат ова можеби го знаат XPath, а некои можеби не. XPath е прилично голема област на технологијата и не можам навистина да ги научам сите основи, а исто така да ви покажам интересни работи што треба да ги правите со него во една статија како оваа. Навистина се обидов да ја напишам таа статија, но просечната публикација на списанието Smashing не надминува 5.000 зборови. Јас веќе бев на повеќе од2.000 зборови додека само на половина пат низ основите. Значи, ќе почнам да правам кул работи со XPath и ќе ви дадам неколку врски што можете да ги користите за основите ако ви се чини дека овие работи ви се интересни. Комбинирање на XPath и CSS XPath може да направи многу работи што селекторите на CSS не можат да ги направат кога бараат елементи. Но, CSS селекторите исто така можат да направат неколку работи што XPath не може, имено, да бара елементи по име на класа.

CSS XPath .myClass /*[содржи(@class, „myClass“)]

Во овој пример, CSS бара елементи кои содржат име на класа .myClass. Во меѓувреме, примерот XPath бара елементи што содржат класа на атрибути со низата „myClass“. Со други зборови, избира елементи со myClass во кој било атрибут, вклучувајќи елементи со име на класа .myClass — како и елементи со „myClass“ во низата, како што е .myClass2. XPath е поширок во таа смисла. Значи, не. Не сугерирам дека треба да го исфрлиме CSS и да почнеме да ги избираме сите елементи преку XPath. Тоа не е поентата. Поентата е дека XPath може да прави работи што CSS не може и сè уште може да биде многу корисна, иако е постара технологија во купот на прелистувачот и можеби не изгледа очигледно на прв поглед. Ајде да ги користиме двете технологии заедно не само затоа што можеме, туку затоа што ќе научиме нешто за XPath во процесот, што ќе го направи уште една алатка во вашиот куп - една за која можеби не сте знаеле дека е таму цело време! Проблемот е што методот document.evaluate на JavaScript и различните методи за избирање прашања што ги користиме со CSS API за JavaScript се некомпатибилни. Направив компатибилен API за барање за да започнеме, иако мора да се признае, не размислував многу за тоа бидејќи тоа е отстапување од она што го правиме овде. Еве еден прилично едноставен работен пример на конструктор за повеќекратно пребарување: Видете го барањето за пенкало XPath [заглавено] од Брајан Расмусен. Додадов два методи на објектот на документот: queryCSSSelectors (што во суштина е querySelectorAll) и queryXPaths. И двете од овие враќаат објект queryResults:

{ queryType: јазли | низа | број | бул, резултати: какви било[] // html елементи, xml елементи, низи, броеви, булови, queryCSSS селектори: (прашање: низа, измени: бул) => queryResults, queryXpaths: (query: string, amend: boolean) => queryResults }

Функциите queryCSSSelectors и queryXpaths го извршуваат барањето што им го давате преку елементите во низата со резултати, сè додека низата резултати е од типот јазли, се разбира. Во спротивно, ќе врати queryResult со празна низа и тип на јазли. Ако својството amend е поставено на точно, функциите ќе ги променат нивните сопствени резултати од барањето. Во никој случај не треба да се користи во производствена средина. Го правам тоа чисто за да ги покажам различните ефекти од користењето на двете API-и за барање заедно. Пример за прашања Сакам да прикажам неколку примери на различни прашања за XPath кои покажуваат некои од моќните работи што можат да ги направат и како може да се користат наместо други пристапи. Првиот пример е //li/text(). Ова ги бара сите li елементи и ги враќа нивните текстуални јазли. Значи, ако го побараме следниот HTML:

  • еден
  • два
  • три

…еве што се враќа:

{"queryType":"xpathEvaluate", "резултати":["еден", "два", "три"],"resultType":"низа"}

Со други зборови, ја добиваме следната низа: ["еден", "два", "три"]. Вообичаено, ќе побарате ли елементите да го добијат тоа, ќе го претворите резултатот од тоа барање во низа, ќе ја мапирате низата и ќе го вратите текстуалниот јазол на секој елемент. Но, можеме да го направиме тоа поконцизно со XPath: document.queryXPaths("//li/text()").резултати.

Забележете дека начинот да се добие текстуален јазол е да се користи text(), кој изгледа како потпис на функција - и тоа е. Го враќа текстуалниот јазол на елементот. Во нашиот пример, има три li елементи во ознаката, од кои секој содржи текст („еден“, „два“ и „три“). Ајде да погледнеме уште еден пример на барање за текст(). Да претпоставиме дека ова е нашата ознака: Најавете се

Ајде да напишеме барање што ја враќа вредноста на атрибутот href: document.queryXPaths("//a[text() = 'Најави се']/@href").резултати.

Ова е барање за XPath на тековниот документ, исто како и последниот пример, но овој пат го враќаме атрибутот href на врската (елемент) што го содржи текстот „Најави се“. Вистинското вратенорезултатот е ["/login.html"]. Преглед на функциите на XPath Постојат голем број XPath функции и веројатно не сте запознаени со нив. Има неколку, мислам, за кои вреди да се знае, вклучувајќи го и следново:

starts-withАко текстот започнува со одреден друг пример за текст, starts-with(@href, 'http:') враќа true ако атрибутот href започнува со http:. содржи Ако текстот содржи одреден друг пример за текст, содржи (текст(), „Списание за кршење“) враќа точно ако текстуалниот јазол ги содржи зборовите „Списание за кршење“ каде било. countВраќа бројка од тоа колку совпаѓања има на барањето. На пример, count(//*[starts-with(@href, 'http:']) враќа бројка за тоа колку врски во контекстниот јазол имаат елементи со атрибут href што го содржи текстот што започнува со http:. substring Работи како подниза JavaScript, освен што ја пренесувате низата како аргумент. На пример, substring ("мојот текст", 2, 4) враќа "y t". substring-before Го враќа делот од низата пред друга низа. На пример, substing-before("мојот текст", " ") враќа "моето". Слично на тоа, substring-before("hi","bye") враќа празен стринг. substring-after Го враќа делот од низата по друга низа. На пример, substing-after("мојот текст", " ") враќа "текст". Слично на тоа, substring-after("hi","bye") враќа празна низа. normalize-space Ја враќа низата аргументи со празно место нормализирано со одземање на празно место во предниот и задоцнето и замена на секвенците од знаци на празно место со едно празно место. неВраќа бул точно ако аргументот е неточен, инаку неточен. true Враќа булова точно. falseВраќа булова неточно. concatИстата работа како JavaScript concat, освен што не ја извршувате како метод на низа. Наместо тоа, ги ставате сите жици што сакате да ги споите. string-lengthОва не е исто како и JavaScript string-length, туку ја враќа должината на низата што е дадена како аргумент. translateThis зема низа и го менува вториот аргумент во трет аргумент. На пример, translate ("abcdef", "abc", "XYZ") излегува XYZdef.

Настрана од овие одредени функции на XPath, постојат голем број други функции кои работат исто како нивните колеги JavaScript - или колеги во основа на кој било програмски јазик - што веројатно исто така ќе ви бидат корисни, како што се подот, таванот, кругот, збирот итн. Следното демо ја илустрира секоја од овие функции: Видете ги нумеричките функции на пенкалото XPath [заглавени] од Брајан Расмусен. Забележете дека, како и повеќето функции за манипулација со низа, многу од нумеричките земаат еден влез. Ова е, се разбира, затоа што тие треба да се користат за барање, како во последниот пример на XPath: //li[floor(text()) > 250]/@val

Ако ги користите, како што прават повеќето примери, ќе го извршите на првиот јазол што одговара на патеката. Исто така, постојат некои функции за конверзија на типови што веројатно треба да ги избегнувате бидејќи JavaScript веќе има свои проблеми со конверзија на типови. Но, може да има моменти кога сакате да конвертирате низа во број за да ја проверите со некој друг број. Функциите што го поставуваат типот на нешто се бул, број, низа и јазол. Ова се важните типови на податоци на XPath. И како што може да замислите, повеќето од овие функции може да се користат на типови на податоци кои не се јазли на DOM. На пример, substring-after зема низа како што веќе опфативме, но тоа може да биде низата од атрибутот href. Може да биде и низа:

const testSubstringAfter = document.queryXPaths("substring-after('здраво свет',' ')");

Очигледно, овој пример ќе ни ја врати низата со резултати како [„свет“]. За да го прикажам ова на дело, направив демо страница користејќи функции против работи што не се јазли на DOM: Видете го барањето за пенкало XPath [заглавено] од Брајан Расмусен. Треба да го забележите изненадувачкиот аспект на функцијата преведување, а тоа е дека ако имате знак во вториот аргумент (т.е. списокот на знаци што сакате да ги преведете) и немате соодветен знак за преведување, тој знак се отстранува од излезот. Така, ова:

преведи ('Здраво, се викам Иниго Монтоја, го уби татко ми, подготви се да умреш','abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,','*')

…резултатите во низата, вклучувајќи празни места: [" * * ** "]

Ова значи дека буквата „a“ се преведува на ѕвездичка (*), но секој друг знак што нема превод со оглед на целната низа е целосно отстранет. Празното место е се што ни останапомеѓу преведените знаци „а“. Потоа повторно, ова прашање:

translate('Здраво, се викам Иниго Монтоја, го уби татко ми, подготви се да умреш','abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,','***************************************************')")

... го нема проблемот и дава резултат кој изгледа вака:

"***** ** **** ** ***** ******* *** ***** ** ***** ***** ** ***"

Може да ве изненади дека не постои лесен начин во JavaScript да се направи токму она што го прави функцијата за преведување XPath, иако за многу случаи на употреба, заменете ги сите со регуларни изрази може да се справи со тоа. Може да го користите истиот пристап што го покажав, но тоа е неоптимално ако сè што сакате е да ги преведете низите. Следното демо ја обвива функцијата за преведување на XPath за да обезбеди верзија на JavaScript: Видете ја функцијата за преведување на пенкало [закопчана] од Брајан Расмусен. Каде можете да користите вакво нешто? Размислете за шифрирање на цифрите на Цезар со поместување од три места (на пр., највисоко шифрирање од 48 п.н.е.):

преведете ("Цезар планира да го премине Рубикон!", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", „XYZABCDEFGHIJKLMNOPQRSTUVWxyzabcdefghijklmnopqrstuvw“)

Влезен текст „Цезар планира да го премине Рубикон!“ резултира со „Zxbpxo fp mixkkfkd ql zolpp qeb Oryfzlk!“ За да дадам уште еден брз пример за различни можности, направив метална функција која зема внесување низа и користи функција за преведување за да го врати текстот, вклучувајќи ги сите знаци што земаат umlauts. Видете ја металната функција за пенкало [закопчана] од Брајан Расмусен.

конст метал = (ул) => { врати превод (ул, "AOUaou", "ÄÖÜäöü"); }

И, ако му се даде текстот „Motley Crue rules, rock on dudes!“, враќа „Mötley Crüe rüles, röck ön düdes!“ Очигледно, некој може да има секакви пародиски употреби на оваа функција. Ако сте вие, тогаш оваа статија на TVTropes треба да ви даде многу инспирација. Користење на CSS со XPath Запомнете ја нашата главна причина за користење на CSS селектори заедно со XPath: CSS прилично разбира што е класа, додека најдоброто што можете да го направите со XPath е споредување низи на атрибутот класа. Тоа ќе функционира во повеќето случаи. Но, ако некогаш наидете на ситуација кога, да речеме, некој создал класи со име .primaryLinks и .primaryLinks2 и вие сте користеле XPath за да ја добиете класата .primaryLinks, тогаш најверојатно ќе наидете на проблеми. Сè додека нема ништо глупо како тоа, веројатно би користеле XPath. Но, со тага можам да известам дека сум работел на места каде што луѓето прават такви глупави работи. Еве уште едно демо кое користи CSS и XPath заедно. Покажува што се случува кога го користиме кодот за да извршиме XPath на контекстен јазол што не е јазол на документот. Видете ги пенкалото css и xpath заедно [заглавени] од Брајан Расмусен. Барањето CSS е .relatedarticles a, кое ги презема двата a елементи во div доделена класа .relatedarticles. После тоа се три „лоши“ прашања, односно прашања кои не го прават она што ние сакаме да го прават кога се извршуваат со овие елементи како контекстен јазол. Можам да објаснам зошто тие се однесуваат поинаку отколку што може да очекувате. Трите лоши прашања за кои станува збор се:

//text(): Го враќа целиот текст во документот. //a/text(): Го враќа целиот текст во внатрешноста на врските во документот. ./a/text(): Не враќа резултати.

Причината за овие резултати е тоа што додека вашиот контекст е елементи вратени од барањето CSS, // оди против целиот документ. Ова е силата на XPath; CSS не може да оди од јазол до предок, а потоа до брат или сестра на тој предок, и да оди надолу до потомок на тој брат или сестра. Но, XPath може. Во меѓувреме, ./ ги прашува децата од тековниот јазол, каде што точката (.) го претставува тековниот јазол, а предната коса коса (/) претставува одење до некој детски јазол - без разлика дали тоа е атрибут, елемент или текст се одредува со следниот дел од патеката. Но, нема дете елемент избран од барањето CSS, така што тоа барање не враќа ништо. Има три добри прашања во последното демо:

.//text(), ./text(), normalize-space(./text()).

Барањето за нормализирање на просторот го демонстрира користењето на функцијата XPath, но исто така поправа проблем вклучен во другите барања. HTML е структуриран вака:

Автоматизирање на тестирањето на вашите карактеристики со Selenium WebDriver

Барањето враќа линија за снабдување на почетокот и крајот на текстуалниот јазол,и normalize-space го отстранува ова. Користењето на која било функција XPath што враќа нешто различно од бул со влез XPath се однесува на други функции. Следното демо прикажува голем број примери: Видете ги примерите на функциите на Pen xpath [закопани] од Брајан Расмусен. Првиот пример покажува проблем на кој треба да внимавате. Поточно, следниот код:

document.queryXPaths("substring-after(//a/@href,'https://')");

…враќа една низа:

"www.smashingmagazine.com/2018/04/feature-testing-selenium-webdriver/"

Има смисла, нели? Овие функции не враќаат низи, туку поединечни низи или единечни броеви. Извршувањето на функцијата насекаде со повеќе резултати го враќа само првиот резултат. Вториот резултат покажува што навистина сакаме:

document.queryCSSSelectors("a").queryXPaths("substring-after(./@href,'https://')");

Што враќа низа од две низи:

["www.smashingmagazine.com/2018/04/feature-testing-selenium-webdriver/","www.smashingmagazine.com/2022/11/automated-test-results-improve-accessibility/"]

Функциите на XPath можат да се вгнездат исто како функциите во JavaScript. Значи, ако ја знаеме структурата на URL-то на Smashing Magazine, би можеле да го направиме следново (се препорачува користење на буквални шаблони): `преведи( подниза ( substring-after(./@href, „www.smashingmagazine.com/“) ,9), '/',')`

Ова станува малку премногу сложено до степен до кој му се потребни коментари што опишуваат што прави: земете ја целата URL-адреса од атрибутот href по www.smashingmagazine.com/, отстранете ги првите девет знаци, а потоа преведете го знакот нанапред (/) на ништо за да се ослободите од крајната коса коса. Резултирачката низа:

["feature-testing-selenium-webdriver", "automated-test-results-improve-accessibility"]

Повеќе случаи за употреба на XPath XPath навистина може да блесне во тестирањето. Причината не е тешко да се види, бидејќи XPath може да се користи за да се добие секој елемент во DOM, од која било позиција во DOM, додека CSS не може. Не можете да сметате на CSS класите да останат конзистентни во многу модерни системи за градење, но со XPath, можеме да направиме поцврсти совпаѓања со тоа што е содржината на текстот на елементот, без оглед на променливата структура на DOM. Имаше истражување за техники кои ви дозволуваат да направите еластични XPath тестови. Ништо не е полошо од тоа што тестовите се шушкаат и не успеваат само затоа што CSS избирачот повеќе не работи затоа што нешто е преименувано или отстрането. XPath е исто така навистина одличен при екстракција на повеќе локатори. Има повеќе од еден начин да се користат барањата на XPath за да се совпадне некој елемент. Истото важи и со CSS. Но, прашањата за XPath можат да ги продлабочат работите на поцелен начин што го ограничува она што се враќа, што ќе ви овозможи да пронајдете одредено совпаѓање каде што може да има неколку можни совпаѓања. На пример, можеме да го користиме XPath за да вратиме специфичен h2 елемент што е содржан во div што веднаш следи див од брат или сестра, кој, пак, содржи елемент од дете-слика со атрибут data-testID = "водач" на него:

не го сфаќајте овој наслов

Не го добивајте ниту овој наслов

Заглавие за сликата на лидерот

Ова е прашањето: document.queryXPaths(` //div[ следен брат::div[1] /img[@data-testID='лидер'] ] /h2/ текст () `);

Ајде да видиме демо за да видиме како сето тоа се спојува: Видете го Прашањето за комплекс на пенкало H2 [заглавено] од Брајан Расмусен. Така, да. Постојат многу можни патеки до кој било елемент во тестот користејќи XPath. XSLT 1.0 Отстранување Рано спомнав дека тимот на Chrome планира да ја отстрани поддршката за XSLT 1.0 од прелистувачот. Тоа е важно затоа што XSLT 1.0 користи програмирање фокусирано на XML за трансформација на документи што, пак, се потпира на XPath 1.0, што е она што се наоѓа во повеќето прелистувачи. Кога тоа ќе се случи, ќе изгубиме клучна компонента на XPath. Но, со оглед на фактот дека XPath е навистина одличен за пишување тестови, сметам дека е малку веројатно дека XPath како целина ќе исчезне наскоро. Како што рече, забележав дека луѓето се интересираат за некоја карактеристика кога ќе биде одземена. И тоа секако е точно во случај кога XSLT 1.0 е застарен. Цела дискусија се случува во Hacker News исполнета со аргументи против отфрлањето. Самиот пост е одличен пример за создавање рамка за блогирање со XSLT. Виеможете сами да ја прочитате дискусијата, но навлегува во тоа како JavaScript може да се користи како шмек за XLST за справување со такви случаи. Сум видел и предлози дека прелистувачите треба да користат SaxonJS, што е порта за Saxon XSLT, XQUERY и XPath моторите на JavaScript. Тоа е интересна идеја, особено затоа што Saxon-JS ја имплементира тековната верзија на овие спецификации, додека не постои прелистувач што имплементира која било верзија на XPath или XSLT над 1.0 и ниту еден што имплементира XQuery. Посегнав до Норм Тови-Волш во Саксоница, компанијата зад SaxonJS и други верзии на саксонскиот мотор. Тој рече: „Доколку некој продавач на прелистувачи беше заинтересиран да го земе SaxonJS како почетна точка за интегрирање на модерните XML технологии во прелистувачот, ние би биле воодушевени да разговараме за тоа со нив“ - Норм Тови-Волш

Но, исто така додаде: „Би бил многу изненаден ако некој помисли дека преземањето на SaxonJS во неговата сегашна форма и фрлањето во верзијата на прелистувачот непроменето ќе биде идеален пристап. Продавачот на прелистувачи, по природа на фактот дека го создава прелистувачот, може да пристапи кон интеграцијата на многу подлабоко ниво отколку што можеме „однадвор““ - Норм Тови-Волш

Вреди да се напомене дека коментарите на Tovey-Walsh дојдоа околу една недела пред објавувањето на XSLT за откажување. Заклучок Можев да продолжам и понатаму. Но, се надевам дека ова ја покажа моќта на XPath и ви даде многу примери кои покажуваат како да го користите за постигнување големи работи. Тоа е совршен пример за постара технологија во купот на прелистувачот што сè уште има многу корисност денес, дури и ако никогаш не сте знаеле дека постои или никогаш не сте размислувале да посегнете по неа. Понатамошно читање

„Подобрување на еластичноста на автоматизираните веб-тестови со природен јазик“ (ACM Дигитална библиотека) од Марун Ајли, Јусеф Бакуни, Надер Џалул и Рима КиланиОваа статија дава многу примери на XPath за пишување еластични тестови. XPath (MDN) Ова е одлично место за почеток доколку сакате техничко објаснување во кое детално ќе се опише како функционира XPath. Упатство за XPath (ZVON) Сфатив дека ова упатство е најкорисно во моето учење, благодарение на мноштвото примери и јасни објаснувања. XPatherОваа интерактивна алатка ви овозможува да работите директно со кодот.

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free